0 | module Pack.Runner.Develop
  1 |
  2 | import Data.IORef
  3 | import Data.SortedMap
  4 | import Idris.Package.Types
  5 | import Pack.Config
  6 | import Pack.Core
  7 | import Pack.Database
  8 | import Pack.Runner.Database
  9 | import Pack.Runner.Install
 10 | import Pack.Runner.Query
 11 |
 12 | %default total
 13 |
 14 | covering
 15 | runIdrisOn :
 16 |      {auto _ : HasIO io}
 17 |   -> {auto _ : IdrisEnv}
 18 |   -> (logLevel   : LogLevel)
 19 |   -> (cleanBuild : Bool)
 20 |   -> (cmd        : CmdArgList)
 21 |   -> Desc Safe
 22 |   -> EitherT PackErr io ()
 23 | runIdrisOn lvl cleanBuild c d@(MkDesc x _ _ _) = do
 24 |   installDeps d
 25 |   info "Building\: \{name x}"
 26 |   libPkg [] lvl cleanBuild c d
 27 |
 28 | findIpkg :
 29 |      {auto _ : HasIO io}
 30 |   -> WithIpkg
 31 |   -> Maybe (File Abs)
 32 |   -> EitherT PackErr io (Maybe $ File Abs)
 33 | findIpkg (Search $ CD dir) fi =
 34 |   let searchDir := maybe dir parent fi
 35 |    in findInParentDirs isIpkgBody searchDir
 36 | findIpkg None         _  = pure Nothing
 37 | findIpkg (Use x)      _  = pure (Just x)
 38 |
 39 | -- returns the direct dependencies to be included in a REPL session
 40 | covering
 41 | replDeps :
 42 |      {auto _ : HasIO io}
 43 |   -> {auto e : IdrisEnv}
 44 |   -> Maybe (Desc Safe)
 45 |   -> Autoload
 46 |   -> EitherT PackErr io (List PkgName)
 47 | replDeps _        (ForcePkgs ps) = pure ps
 48 | replDeps (Just d) _              = pure $ dependencies d
 49 | replDeps Nothing  NoPkgs         = pure $ []
 50 | replDeps Nothing  AutoLibs       = pure $ e.env.config.autoLibs
 51 | replDeps Nothing  (AutoPkgs ps)  = pure $ ps
 52 | replDeps Nothing  Installed      =
 53 |   map name . filter installedLib . snd <$> resolveAll
 54 |
 55 | covering
 56 | replOpts :
 57 |      {auto _ : HasIO io}
 58 |   -> {auto e : IdrisEnv}
 59 |   -> (file : Maybe $ File Abs)
 60 |   -> EitherT PackErr io (CmdArgList, Codegen, Maybe $ File Abs)
 61 | replOpts mf = do
 62 |   mp   <- findIpkg e.env.config.withIpkg mf
 63 |   for_ mp $ \p => info "Found `.ipkg` file at \{p}"
 64 |   md   <- traverse (\p => parseLibIpkg p p) mp
 65 |   libs <- map (Library,) <$> replDeps md e.env.config.autoLoad
 66 |   tds  <- mapMaybe libName <$> transitiveDeps libs
 67 |
 68 |   let srcDir := maybe [] (\s => ["--source-dir", s]) (md >>= sourcedir . desc)
 69 |       pkgs   := concatMap (\td => ["-p", value td]) tds
 70 |       cg     := maybe e.env.config.codegen (ipkgCodeGen . desc) md
 71 |       cgOpt  := case cg of
 72 |                   Default => []
 73 |                   _       => ["--cg", cg]
 74 |   install libs
 75 |   pure (srcDir ++ cgOpt ++ pkgs, cg, mp)
 76 |
 77 | -- return the path of an Idris source file to an `.ipkg` file.
 78 | srcFileRelativeToIpkg : (ipkg,idr : Maybe (File Abs)) -> CmdArgList
 79 | srcFileRelativeToIpkg _           Nothing    = []
 80 | srcFileRelativeToIpkg Nothing     (Just idr) = [ idr ]
 81 | srcFileRelativeToIpkg (Just ipkg) (Just idr) =
 82 |   let rel := relativeTo ipkg.parent idr.parent
 83 |    in [ MkF rel idr.file ]
 84 |
 85 | ||| Use the installed Idris to start a REPL session with the
 86 | ||| given argument string.
 87 | export covering
 88 | idrisRepl :
 89 |      {auto _ : HasIO io}
 90 |   -> (file : Maybe $ File Abs)
 91 |   -> IdrisEnv
 92 |   -> EitherT PackErr io ()
 93 | idrisRepl mf e = do
 94 |   (opts, _, mp) <- replOpts mf
 95 |   env  <- buildEnv
 96 |
 97 |   let arg := srcFileRelativeToIpkg mp mf
 98 |       exe := idrisWithCG
 99 |
100 |   cmd <- case e.env.config.rlwrap of
101 |     UseRlwrap rargs => pure $ ["rlwrap"] ++ rargs ++ exe ++ opts ++ arg
102 |     DoNotUseRlwrap  => pure $ exe ++ opts ++ arg
103 |
104 |   case mp of
105 |     Just af => inDir af.parent $ \_ => sysWithEnv cmd env
106 |     Nothing => sysWithEnv cmd env
107 |
108 | ||| Use the installed Idris to compile the given source file
109 | ||| and invoke its main function with the given argument list.
110 | export covering
111 | exec :
112 |      {auto _ : HasIO io}
113 |   -> (file : File Abs)
114 |   -> (args : CmdArgList)
115 |   -> IdrisEnv
116 |   -> EitherT PackErr io ()
117 | exec file args e = do
118 |   (opts, cg, mp) <- replOpts (Just file)
119 |   env  <- buildEnv
120 |
121 |   let interp  := case cg of
122 |          Node => ["node"]
123 |          _    => []
124 |       relFile := srcFileRelativeToIpkg mp (Just file)
125 |       exe     := idrisWithCG
126 |       cmd     := exe ++ opts ++ ["-o", e.env.config.output] ++ relFile
127 |       run     := interp ++ ["build/exec/\{e.env.config.output}"] ++ args
128 |
129 |   case mp of
130 |     Just af => inDir af.parent $ \_ => do
131 |       sysWithEnvAndLog Build cmd env
132 |       sys run
133 |     Nothing => sysWithEnvAndLog Build cmd env >> sys run
134 |
135 | ||| Build a local library given as an `.ipkg` file.
136 | export covering %inline
137 | build : HasIO io => PkgOrIpkg -> IdrisEnv -> EitherT PackErr io ()
138 | build f e = findAndParseLocalIpkg f >>= runIdrisOn Build True ["--build"]
139 |
140 | ||| Install dependencies of a local `.ipkg` file or package name
141 | export covering
142 | buildDeps : HasIO io => PkgOrIpkg -> IdrisEnv -> EitherT PackErr io ()
143 | buildDeps f e = do
144 |   d <- findAndParseLocalIpkg f
145 |   installDeps d
146 |
147 | ||| Typecheck a local library given as an `.ipkg` file or package name
148 | export covering %inline
149 | typecheck : HasIO io => PkgOrIpkg -> IdrisEnv -> EitherT PackErr io ()
150 | typecheck f e =
151 |   findAndParseLocalIpkg f >>= runIdrisOn Build True ["--typecheck"]
152 |
153 | ||| Cleanup a local library given as an `.ipkg` file or package name
154 | export covering %inline
155 | clean : HasIO io => PkgOrIpkg -> IdrisEnv -> EitherT PackErr io ()
156 | clean f e = do
157 |   p <- findAndParseLocalIpkg f
158 |   libPkg [] Build False ["--clean"] p
159 |   rmDir (buildPath p)
160 |
161 | ||| Build and execute a local `.ipkg` file.
162 | export covering
163 | runIpkg :
164 |      {auto _ : HasIO io}
165 |   -> File Abs
166 |   -> (args : CmdArgList)
167 |   -> IdrisEnv
168 |   -> EitherT PackErr io ()
169 | runIpkg p args e = do
170 |   d        <- parseLibIpkg p p
171 |   Just exe <- pure (execPath d) | Nothing => throwE (NoAppIpkg p)
172 |   build (Ipkg p) e
173 |   case ipkgCodeGen d.desc of
174 |     Node => sys $ ["node", exe] ++ args
175 |     _    => sys $ [exe] ++ args
176 |
177 | ||| Build and execute the test suite of a package.
178 | export covering
179 | runTest :
180 |      {auto _ : HasIO io}
181 |   -> PkgName
182 |   -> (args : CmdArgList)
183 |   -> IdrisEnv
184 |   -> EitherT PackErr io ()
185 | runTest n args e = case lookup n e.env.all of
186 |   Nothing                     => throwE (UnknownPkg n)
187 |   Just (Git u c _ _ (Just t) _) => do
188 |     d <- withGit n u c False pure
189 |     runIpkg (d </> t) args e
190 |   Just (Local d _ _ $ Just t) => runIpkg (d </> t) args e
191 |   Just _                      => do
192 |     warn "No test suite found for \{n}. I'll just typecheck it."
193 |     typecheck (Pkg n) e
194 |
195 | ||| Install and run an executable given as a package name.
196 | export covering
197 | execApp :
198 |      {auto _ : HasIO io}
199 |   -> PkgName
200 |   -> (args : CmdArgList)
201 |   -> IdrisEnv
202 |   -> EitherT PackErr io ()
203 | execApp p args e = do
204 |   ref <- emptyCache
205 |   ra <- resolveApp p
206 |   install [(App False,p)]
207 |   case ipkgCodeGen ra.desc.desc of
208 |     Node => sys $ ["node", pkgExec ra.name ra.hash ra.pkg ra.exec] ++ args
209 |     _    => sys $ [pkgExec ra.name ra.hash ra.pkg ra.exec] ++ args
210 |
211 | export covering
212 | runApp :
213 |      {auto _ : HasIO io}
214 |   -> PkgOrIpkg
215 |   -> (args : CmdArgList)
216 |   -> IdrisEnv
217 |   -> EitherT PackErr io ()
218 | runApp (Pkg p)  = execApp p
219 | runApp (Ipkg p) = runIpkg p
220 |