Skip to content

Commit 3c61804

Browse files
committed
track if srcDir is absolute or relative
These changes are necessary for when `elm make src/Main.elm` is run with (1) absolute source directories and (2) source directories that contain .. or . in them.
1 parent c76acf6 commit 3c61804

File tree

5 files changed

+207
-86
lines changed

5 files changed

+207
-86
lines changed

builder/src/Build.hs

+83-68
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import qualified Elm.Details as Details
4242
import qualified Elm.Docs as Docs
4343
import qualified Elm.Interface as I
4444
import qualified Elm.ModuleName as ModuleName
45+
import qualified Elm.Outline as Outline
4546
import qualified Elm.Package as Pkg
4647
import qualified File
4748
import qualified Json.Encode as E
@@ -65,21 +66,46 @@ data Env =
6566
{ _key :: Reporting.BKey
6667
, _root :: FilePath
6768
, _project :: Parse.ProjectType
68-
, _srcDirs :: [FilePath]
69+
, _srcDirs :: [AbsoluteSrcDir]
6970
, _buildID :: Details.BuildID
7071
, _locals :: Map.Map ModuleName.Raw Details.Local
7172
, _foreigns :: Map.Map ModuleName.Raw Details.Foreign
7273
}
7374

7475

75-
makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> Env
76+
makeEnv :: Reporting.BKey -> FilePath -> Details.Details -> IO Env
7677
makeEnv key root (Details.Details _ validOutline buildID locals foreigns _) =
7778
case validOutline of
78-
Details.ValidApp srcDirs ->
79-
Env key root Parse.Application (NE.toList srcDirs) buildID locals foreigns
79+
Details.ValidApp givenSrcDirs ->
80+
do srcDirs <- traverse (toAbsoluteSrcDir root) (NE.toList givenSrcDirs)
81+
return $ Env key root Parse.Application srcDirs buildID locals foreigns
8082

8183
Details.ValidPkg pkg _ _ ->
82-
Env key root (Parse.Package pkg) ["src"] buildID locals foreigns
84+
do srcDir <- toAbsoluteSrcDir root (Outline.RelativeSrcDir "src")
85+
return $ Env key root (Parse.Package pkg) [srcDir] buildID locals foreigns
86+
87+
88+
89+
-- SOURCE DIRECTORY
90+
91+
92+
newtype AbsoluteSrcDir =
93+
AbsoluteSrcDir FilePath
94+
95+
96+
toAbsoluteSrcDir :: FilePath -> Outline.SrcDir -> IO AbsoluteSrcDir
97+
toAbsoluteSrcDir root srcDir =
98+
AbsoluteSrcDir <$> Dir.canonicalizePath
99+
(
100+
case srcDir of
101+
Outline.AbsoluteSrcDir dir -> dir
102+
Outline.RelativeSrcDir dir -> root </> dir
103+
)
104+
105+
106+
addRelative :: AbsoluteSrcDir -> FilePath -> FilePath
107+
addRelative (AbsoluteSrcDir srcDir) path =
108+
srcDir </> path
83109

84110

85111

@@ -110,7 +136,7 @@ forkWithKey func dict =
110136
fromExposed :: Reporting.Style -> FilePath -> Details.Details -> DocsGoal docs -> NE.List ModuleName.Raw -> IO (Either Exit.BuildProblem docs)
111137
fromExposed style root details docsGoal exposed@(NE.List e es) =
112138
Reporting.trackBuild style $ \key ->
113-
do let env = makeEnv key root details
139+
do env <- makeEnv key root details
114140
dmvar <- Details.loadInterfaces root details
115141

116142
-- crawl
@@ -161,7 +187,7 @@ type Dependencies =
161187
fromMains :: Reporting.Style -> FilePath -> Details.Details -> NE.List FilePath -> IO (Either Exit.BuildProblem Artifacts)
162188
fromMains style root details paths =
163189
Reporting.trackBuild style $ \key ->
164-
do let env = makeEnv key root details
190+
do env <- makeEnv key root details
165191

166192
elmains <- findMains env paths
167193
case elmains of
@@ -241,9 +267,8 @@ crawlDeps env mvar deps blockedValue =
241267
crawlModule :: Env -> MVar StatusDict -> DocsNeed -> ModuleName.Raw -> IO Status
242268
crawlModule env@(Env _ root projectType srcDirs buildID locals foreigns) mvar docsNeed name =
243269
do let fileName = ModuleName.toFilePath name <.> "elm"
244-
let inRoot path = File.exists (root </> path)
245270

246-
paths <- filterM inRoot (map (</> fileName) srcDirs)
271+
paths <- filterM File.exists (map (`addRelative` fileName) srcDirs)
247272

248273
case paths of
249274
[path] ->
@@ -263,7 +288,7 @@ crawlModule env@(Env _ root projectType srcDirs buildID locals foreigns) mvar do
263288
else crawlDeps env mvar deps (SCached local)
264289

265290
p1:p2:ps ->
266-
return $ SBadImport $ Import.AmbiguousLocal p1 p2 ps
291+
return $ SBadImport $ Import.AmbiguousLocal (FP.makeRelative root p1) (FP.makeRelative root p2) (map (FP.makeRelative root) ps)
267292

268293
[] ->
269294
case Map.lookup name foreigns of
@@ -856,35 +881,33 @@ data ReplArtifacts =
856881

857882
fromRepl :: FilePath -> Details.Details -> B.ByteString -> IO (Either Exit.Repl ReplArtifacts)
858883
fromRepl root details source =
859-
let
860-
env@(Env _ _ projectType _ _ _ _) = makeEnv Reporting.ignorer root details
861-
in
862-
case Parse.fromByteString projectType source of
863-
Left syntaxError ->
864-
return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
884+
do env@(Env _ _ projectType _ _ _ _) <- makeEnv Reporting.ignorer root details
885+
case Parse.fromByteString projectType source of
886+
Left syntaxError ->
887+
return $ Left $ Exit.ReplBadInput source $ Error.BadSyntax syntaxError
865888

866-
Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
867-
do dmvar <- Details.loadInterfaces root details
889+
Right modul@(Src.Module _ _ _ imports _ _ _ _ _) ->
890+
do dmvar <- Details.loadInterfaces root details
868891

869-
let deps = map Src.getImportName imports
870-
mvar <- newMVar Map.empty
871-
crawlDeps env mvar deps ()
892+
let deps = map Src.getImportName imports
893+
mvar <- newMVar Map.empty
894+
crawlDeps env mvar deps ()
872895

873-
statuses <- traverse readMVar =<< readMVar mvar
874-
midpoint <- checkMidpoint dmvar statuses
896+
statuses <- traverse readMVar =<< readMVar mvar
897+
midpoint <- checkMidpoint dmvar statuses
875898

876-
case midpoint of
877-
Left problem ->
878-
return $ Left $ Exit.ReplProjectProblem problem
899+
case midpoint of
900+
Left problem ->
901+
return $ Left $ Exit.ReplProjectProblem problem
879902

880-
Right foreigns ->
881-
do rmvar <- newEmptyMVar
882-
resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
883-
putMVar rmvar resultMVars
884-
results <- traverse readMVar resultMVars
885-
writeDetails root details results
886-
depsStatus <- checkDeps root resultMVars deps 0
887-
finalizeReplArtifacts env source modul depsStatus resultMVars results
903+
Right foreigns ->
904+
do rmvar <- newEmptyMVar
905+
resultMVars <- forkWithKey (checkModule env foreigns rmvar) statuses
906+
putMVar rmvar resultMVars
907+
results <- traverse readMVar resultMVars
908+
writeDetails root details results
909+
depsStatus <- checkDeps root resultMVars deps 0
910+
finalizeReplArtifacts env source modul depsStatus resultMVars results
888911

889912

890913
finalizeReplArtifacts :: Env -> B.ByteString -> Src.Module -> DepsStatus -> ResultDict -> Map.Map ModuleName.Raw Result -> IO (Either Exit.Repl ReplArtifacts)
@@ -997,45 +1020,39 @@ findLoc (Env _ root _ srcDirs _ _ _) path absolutePath =
9971020
return $ Left $ Exit.BP_WithBadExtension path
9981021
else
9991022
let
1000-
roots = FP.splitDirectories root
1001-
segments = FP.splitDirectories dirs ++ [final]
1023+
absoluteSegments = FP.splitDirectories dirs ++ [final]
10021024
in
1003-
case dropPrefix roots segments of
1004-
Nothing ->
1025+
case Maybe.mapMaybe (isInsideSrcDirByPath absoluteSegments) srcDirs of
1026+
[] ->
10051027
return $ Right $ Location absolutePath path (LOutside path)
10061028

1007-
Just relativeSegments ->
1008-
case Maybe.mapMaybe (isInsideSrcDirByPath relativeSegments) srcDirs of
1009-
[] ->
1010-
return $ Right $ Location absolutePath path (LOutside path)
1011-
1012-
[(_, Right names)] ->
1013-
do let name = Name.fromChars (List.intercalate "." names)
1014-
matchingDirs <- filterM (isInsideSrcDirByName root names) srcDirs
1015-
case matchingDirs of
1016-
d1:d2:_ ->
1017-
do let p1 = d1 </> FP.joinPath names <.> "elm"
1018-
let p2 = d2 </> FP.joinPath names <.> "elm"
1019-
return $ Left $ Exit.BP_MainNameDuplicate name p1 p2
1029+
[(_, Right names)] ->
1030+
do let name = Name.fromChars (List.intercalate "." names)
1031+
matchingDirs <- filterM (isInsideSrcDirByName names) srcDirs
1032+
case matchingDirs of
1033+
d1:d2:_ ->
1034+
do let p1 = addRelative d1 (FP.joinPath names <.> "elm")
1035+
let p2 = addRelative d2 (FP.joinPath names <.> "elm")
1036+
return $ Left $ Exit.BP_MainNameDuplicate name p1 p2
10201037

1021-
_ ->
1022-
return $ Right $ Location absolutePath path (LInside name)
1038+
_ ->
1039+
return $ Right $ Location absolutePath path (LInside name)
10231040

1024-
[(s, Left names)] ->
1025-
return $ Left $ Exit.BP_MainNameInvalid path s names
1041+
[(s, Left names)] ->
1042+
return $ Left $ Exit.BP_MainNameInvalid path s names
10261043

1027-
(s1,_):(s2,_):_ ->
1028-
return $ Left $ Exit.BP_WithAmbiguousSrcDir path s1 s2
1044+
(s1,_):(s2,_):_ ->
1045+
return $ Left $ Exit.BP_WithAmbiguousSrcDir path s1 s2
10291046

10301047

10311048

1032-
isInsideSrcDirByName :: FilePath -> [String] -> FilePath -> IO Bool
1033-
isInsideSrcDirByName root names srcDir =
1034-
File.exists (root </> srcDir </> FP.joinPath names <.> "elm")
1049+
isInsideSrcDirByName :: [String] -> AbsoluteSrcDir -> IO Bool
1050+
isInsideSrcDirByName names srcDir =
1051+
File.exists (addRelative srcDir (FP.joinPath names <.> "elm"))
10351052

10361053

1037-
isInsideSrcDirByPath :: [String] -> FilePath -> Maybe (FilePath, Either [String] [String])
1038-
isInsideSrcDirByPath segments srcDir =
1054+
isInsideSrcDirByPath :: [String] -> AbsoluteSrcDir -> Maybe (FilePath, Either [String] [String])
1055+
isInsideSrcDirByPath segments (AbsoluteSrcDir srcDir) =
10391056
case dropPrefix (FP.splitDirectories srcDir) segments of
10401057
Nothing ->
10411058
Nothing
@@ -1056,20 +1073,18 @@ isGoodName name =
10561073
Char.isUpper char && all (\c -> Char.isAlphaNum c || c == '_') chars
10571074

10581075

1076+
-- INVARIANT: Dir.canonicalizePath has been run on both inputs
1077+
--
10591078
dropPrefix :: [FilePath] -> [FilePath] -> Maybe [FilePath]
10601079
dropPrefix roots paths =
10611080
case roots of
10621081
[] ->
10631082
Just paths
10641083

1065-
".":rs ->
1066-
dropPrefix rs paths
1067-
10681084
r:rs ->
10691085
case paths of
1070-
[] -> Nothing
1071-
".":ps -> dropPrefix roots ps
1072-
p:ps -> if r == p then dropPrefix rs ps else Nothing
1086+
[] -> Nothing
1087+
p:ps -> if r == p then dropPrefix rs ps else Nothing
10731088

10741089

10751090

builder/src/Elm/Details.hs

+1-1
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ type BuildID = Word64
7979

8080

8181
data ValidOutline
82-
= ValidApp (NE.List FilePath)
82+
= ValidApp (NE.List Outline.SrcDir)
8383
| ValidPkg Pkg.Name [ModuleName.Raw] (Map.Map Pkg.Name V.Version {- for docs in reactor -})
8484

8585

0 commit comments

Comments
 (0)