Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Import local packages as Location #301

Merged
merged 33 commits into from
Jul 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
2337b6a
Move surroundQuote to Prelude
f-f Jul 4, 2019
606d999
Start parsing local packages refs with 'as Location'
f-f Jul 4, 2019
f178f00
Fix `spago list-packages --json` format
f-f Jul 4, 2019
f48dff9
Actually read dependencies from local spago configs
f-f Jul 4, 2019
cfa28d7
Fix tests
f-f Jul 5, 2019
b12ea08
Fix import resolution for local packages
f-f Jul 5, 2019
bf71f81
Merge
f-f Jul 8, 2019
ef40ece
Fix warnings
f-f Jul 8, 2019
d5a0601
Nice error messages
f-f Jul 8, 2019
4c42dea
Update README for the new local packages and add a dedicated monorepo…
f-f Jul 8, 2019
525f515
Merge branch 'master' into local-packages-with-location
f-f Jul 9, 2019
30e0fac
Merge branch 'master' into local-packages-with-location
f-f Jul 10, 2019
5d6fda9
Merge branch 'master' into local-packages-with-location
f-f Jul 10, 2019
a7a2648
Merge branch 'master' into local-packages-with-location
f-f Jul 10, 2019
801d59d
Fix import
f-f Jul 10, 2019
cf9d955
Fix local dependency tests (#311)
elliotdavies Jul 10, 2019
2c12708
Merge branch 'master' into local-packages-with-location
f-f Jul 14, 2019
4c8c9e2
Merge branch 'master' into local-packages-with-location
f-f Jul 14, 2019
1f221b8
Merge branch 'master' into local-packages-with-location
f-f Jul 14, 2019
df15b1d
Merge branch 'master' into local-packages-with-location
f-f Jul 17, 2019
951ba80
Merge branch 'master' into local-packages-with-location
f-f Jul 19, 2019
4bf7111
Merge branch 'master' into local-packages-with-location
f-f Jul 19, 2019
d19cdbc
Merge branch 'master' into local-packages-with-location
f-f Jul 22, 2019
3bd5683
Fix import list
f-f Jul 22, 2019
2387d5f
Merge remote-tracking branch 'origin/master' into local-packages-with…
f-f Jul 22, 2019
e2e2a0f
Merge branch 'master' into local-packages-with-location
f-f Jul 24, 2019
93b2b48
Upgrade to latest package set
f-f Jul 25, 2019
2b4e128
Upgrade to latest dhall-haskell commit
f-f Jul 25, 2019
15ef2da
Merge branch 'master' into local-packages-with-location
f-f Jul 27, 2019
f94889d
Merge remote-tracking branch 'origin/master' into local-packages-with…
f-f Jul 27, 2019
408087f
Remove dependency on lens and use existing Bower machinery for the Bo…
f-f Jul 27, 2019
5f7b365
Merge branch 'master' into local-packages-with-location
f-f Jul 28, 2019
6d6d97f
Switch to upstream dhall package
f-f Jul 29, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 76 additions & 77 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -283,8 +283,8 @@ This is just a thin layer above the PureScript compiler command `purs compile`.
The build will produce very many JavaScript files in the `output/` folder. These
are CommonJS modules, and you can just `require()` them e.g. on Node.

It's also possible to include custom source paths when building (`src` and `test`
are always included):
It's also possible to include custom source paths when building (the ones declared in your
`sources` config are always included):

```bash
$ spago build --path 'another_source/**/*.purs'
Expand Down Expand Up @@ -406,13 +406,14 @@ Now if I want to test this version in my current project, how can I tell `spago`

We have a `overrides` record in `packages.dhall` just for that!

In this case we override the `repo` key with the local path of the package.
In this case we override the package with its local copy, which must have a `spago.dhall`.
(it should be enough to do `spago init` to have the Bower configuration imported)

It might look like this:

```haskell
let overrides =
{ simple-json =
upstream.simple-json // { repo = "../purescript-simple-json" }
{ simple-json = ../purescript-simple-json/spago.dhall as Location
}
```

Expand All @@ -423,26 +424,14 @@ $ spago list-packages
...
signal v10.1.0 Remote "https://github.com/bodil/purescript-signal.git"
sijidou v0.1.0 Remote "https://github.com/justinwoo/purescript-sijidou.git"
simple-json v4.4.0 Local "../purescript-simple-json"
simple-json local Local "./../purescript-simple-json"
simple-json-generics v0.1.0 Remote "https://github.com/justinwoo/purescript-simple-json-generics.git"
smolder v11.0.1 Remote "https://github.com/bodil/purescript-smolder.git"
...
```

And since local packages are just included in the build, if we add it to the `dependencies`
in `spago.dhall` and then do `spago install`, it will not be downloaded:

```
$ spago install
Installing 42 dependencies.
...
Installing "refs"
Installing "identity"
Skipping package "simple-json", using local path: "../purescript-simple-json"
Installing "control"
Installing "enums"
...
```
in `spago.dhall` and then do `spago install`, it will not be downloaded.


### Override a package in the package set with a remote one
Expand Down Expand Up @@ -497,22 +486,13 @@ let additions =
}
```

Of course this works also in the case of adding local packages. In this case you won't
care about the value of the "version" (since it won't be used), so you can put arbitrary
values in there.

And of course if the package you're adding has a `spago.dhall` file you can just import it
and pull the dependencies from there, instead of typing down the list of dependencies!
Of course this works also in the case of adding local packages, which work exactly as the `overrides`:

Example:

```haskell
let additions =
{ foobar =
mkPackage
(../foobar/spago.dhall).dependencies
"../foobar"
"local-fix-whatever"
{ foobar = ../foobar/spago.dhall as Location
}
```

Expand Down Expand Up @@ -571,77 +551,107 @@ let upstream =
```


### Separate `devDependencies` or test dependencies
### Monorepo

`spago` aims to support monorepos. This means that supporting "split" dependencies between tests
and apps or just for dev can be handled as a "monorepo situation".
Spago aims to support ["monorepos"][luu-monorepo], allowing you to split a blob of code
into different "compilation units" that might have different dependencies, deliverables, etc.

So for example if you wish to separate dependencies for some `app` and `lib` you're working on,
you can handle it by having multiple `spago.dhall` config files for the lib and the executable.
A typical monorepo setup in spago consists of:
- some "libraries" (i.e. packages that other packages will depend on), each having their own `spago.dhall`
- some "apps" (i.e. packages that no one depends on), each having their own `spago.dhall`
- a single `packages.dhall` , that includes all the "libraries" as local packages, and that
all `spago.dhall` files refer to - this is so that all packages share the same package set.

E.g. let's say you have the following tree:
So for example if you have `lib1`, `lib2` and `app1`, you might have the following file tree:

```
.
├── app
├── app1
│ ├── spago.dhall
│ ├── src
│ │ └── Main.purs
│ └── test
│ └── Main.purs
├── lib
├── lib1
│ ├── spago.dhall
│ ├── src
│ │ └── Main.purs
│ └── test
│ └── src
│ └── Main.purs
├── lib2
│ ├── spago.dhall
│ └── src
│ └── Main.purs
└── packages.dhall
```

Then:
- the top level `packages.dhall` is standard and contains the link to the upstream and project-level overrides, etc
- `lib/spago.dhall` might look something like this:
- the top level `packages.dhall` might look like this:

```hs
```dhall
let upstream = https://raw.githubusercontent.com/purescript/package-sets/psc-0.13.0-20190626/src/packages.dhall sha256:9905f07c9c3bd62fb3205e2108515811a89d55cff24f4341652f61ddacfcf148

let overrides =
{ lib1 = ./lib1/spago.dhall as Location
, lib2 = ./lib2/spago.dhall as Location
}

in upstream // overrides
```

- `lib1/spago.dhall` might look something like this:

```dhall
{ name =
"my-lib"
"lib1"
, dependencies =
[ "effect"
, "console"
, "psci-support"
, "prelude"
]
, sources =
[ "src/**/*.purs" ]
, packages =
../packages.dhall -- Note: this refers to the top-level packages file
}
```

- `app/spago.dhall` might look something like this:
- assuming `lib1` depends on `lib2`, `lib2/spago.dhall` might look something like this:

```dhall
{ name =
"lib2"
, dependencies =
[ "effect"
, "console"
, "prelude"
, "lib1" -- Note the dependency here
]
, sources =
[ "src/**/*.purs" ]
, packages =
../packages.dhall
}
```

- and then `app1/spago.dhall` might look something like this:

```hs
{ name =
"my-app"
"app1"
, dependencies =
-- Note: the app does not include all the dependencies that the lib included
[ "prelude"
, "simple-json" -- Note: this dep was not used by the library, only the executable uses it
, "my-lib" -- Note: we add the library as dependency
, "simple-json" -- Note: this dep was not used by the library, only the app uses it
, "lib2" -- Note: we add `lib2` as dependency
]
, packages =
-- We refer to the top-level packages file here too, so deps stay in sync
-- and we also add the library as a local package
(../packages.dhall) //
{ my-lib =
{ repo = "../my-lib"
, version = ""
, dependencies = (../my-lib/spago.dhall).dependencies
}
}
-- We also refer to the top-level packages file here, so deps stay in sync for all packages
../packages.dhall
}
```

With this setup you're able to decouple dependencies in the library and in the executables.

Note that you can also handle as a "monorepo" a simpler situation where you want to "split"
dependencies, so e.g. if you want to not include your test dependencies in your app's
dependencies, you can have a "test" project depend on the "app" project.

### Bundle a project into a single JS file

Expand Down Expand Up @@ -793,9 +803,11 @@ do
done
```
### Know what `purs` commands are run under the hood
### Know which `purs` commands are run under the hood
The `-v` flag will print out all the `purs` commands that `spago` invokes during its operations.
The `-v` flag will print out all the `purs` commands that `spago` invokes during its operations,
plus a lot of diagnostic info, so you might want to use it to troubleshoot weird behaviours
and/or crashes.
### Ignore or update the global cache
Expand Down Expand Up @@ -940,20 +952,6 @@ global cache kind of useless. So we are just caching all of that info for everyo
## Troubleshooting
#### I added a git repo URL to my overrides, but `spago` thinks it's a local path 🤔

This might happen if you copy the "git" URL from a GitHub repo and try adding it as a repo URL
in your package set.

However, `spago` requires URLs to conform to [RFC 3986](https://tools.ietf.org/html/rfc3986),
which something like `git@foo.com:bar/baz.git` doesn't conform to.
To have the above repo location accepted you should rewrite it like this:
```
ssh://git@foo.com/bar/baz.git
```
#### Spago is failing with some errors about "too many open files"
This might happen because the limit of "open files per process" is too low in your OS - as
Expand Down Expand Up @@ -1012,6 +1010,7 @@ See [this document](./INTERNALS.md)
[purescript]: https://github.com/purescript/purescript
[psc-package]: https://github.com/purescript/psc-package
[contributing]: CONTRIBUTING.md
[luu-monorepo]: https://danluu.com/monorepo/
[package-sets]: https://github.com/purescript/package-sets
[travis-spago]: https://travis-ci.com/spacchetti/spago
[spago-issues]: https://github.com/spacchetti/spago/issues
Expand Down
31 changes: 15 additions & 16 deletions app/Curator.hs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ import qualified System.Environment as Env
import qualified System.IO.Temp as Temp
import qualified System.Process as Process
import qualified Turtle
import qualified Spago.Config

import Data.Aeson.Encode.Pretty (encodePretty)
import Spago.GlobalCache
import Spago.PackageSet (Package (..), PackageName (..), Repo (..))
import Spago.PackageSet (Package (..), PackageName (..), Repo (..), PackageLocation(..))

type Expr = Dhall.DhallExpr Dhall.Import
type PackageSetMap = Map PackageName Package
Expand Down Expand Up @@ -195,8 +196,8 @@ spagoUpdater token controlChan fetcherChan = go Nothing
go $ Just releaseTagName


fetcher :: Text -> Queue.TBQueue FetcherMessage -> Queue.TQueue MetadataUpdaterMessage -> Queue.TQueue PackageSetsUpdaterMessage -> IO b
fetcher token controlChan metadataChan psChan = forever $ do
fetcher :: MonadIO m => Text -> Queue.TBQueue FetcherMessage -> Queue.TQueue MetadataUpdaterMessage -> Queue.TQueue PackageSetsUpdaterMessage -> m b
fetcher token controlChan metadataChan psChan = liftIO $ forever $ do
(atomically $ Queue.readTBQueue controlChan) >>= \case
MPackageSetTag tag -> do
echo "Downloading and parsing package set.."
Expand All @@ -215,10 +216,10 @@ fetcher token controlChan metadataChan psChan = forever $ do

where
-- | Call GitHub to get metadata for a single package
fetchRepoMetadata :: (PackageName, Package) -> IO ()
fetchRepoMetadata (_, Package{ repo = Local _, ..}) = pure ()
fetchRepoMetadata (packageName, Package{ repo = Remote repoUrl, .. }) =
Retry.recoverAll (Retry.fullJitterBackoff 50000 <> Retry.limitRetries 25) $ \Retry.RetryStatus{..} -> do
fetchRepoMetadata :: MonadIO m => (PackageName, Package) -> m ()
fetchRepoMetadata (_, Package{ location = Local{..}, ..}) = pure ()
fetchRepoMetadata (packageName, Package{ location = Remote{ repo = Repo repoUrl, ..}, ..}) =
liftIO $ Retry.recoverAll (Retry.fullJitterBackoff 50000 <> Retry.limitRetries 25) $ \Retry.RetryStatus{..} -> do
let !(owner:repo:_rest)
= Text.split (=='/')
$ Text.replace "https://github.com/" ""
Expand Down Expand Up @@ -249,15 +250,13 @@ fetcher token controlChan metadataChan psChan = forever $ do
atomically $ Queue.writeTQueue metadataChan $ MMetadata packageName RepoMetadataV1{..}

-- | Tries to read in a PackageSet from GitHub
fetchPackageSet :: Text -> IO PackageSetMap
fetchPackageSet :: MonadIO m => MonadThrow m => Text -> m PackageSetMap
fetchPackageSet tag = do
let packageTyp = Dhall.genericAuto :: Dhall.Type Package
expr <- Dhall.inputExpr ("https://raw.githubusercontent.com/purescript/package-sets/" <> tag <> "/src/packages.dhall")
Right packageSet <- pure $ case expr of
Dhall.RecordLit pkgs -> (Map.mapKeys PackageName . Dhall.Map.toMap)
<$> traverse (Dhall.coerceToType packageTyp) pkgs
something -> Left $ Dhall.PackagesIsNotRecord something
pure packageSet
expr <- liftIO $ Dhall.inputExpr ("https://raw.githubusercontent.com/purescript/package-sets/" <> tag <> "/src/packages.dhall")
case expr of
Dhall.RecordLit pkgs -> fmap (Map.mapKeys PackageName . Dhall.Map.toMap)
$ traverse Spago.Config.parsePackage pkgs
something -> throwM $ Dhall.PackagesIsNotRecord something


packageSetsUpdater :: Text -> Queue.TQueue PackageSetsUpdaterMessage -> IO ()
Expand All @@ -283,7 +282,7 @@ packageSetsUpdater token dataChan = go mempty mempty
case Map.lookup packageName packageSet of
-- We're only interested in the case in which the tag in the package set
-- is different from the current tag.
Just Package{ version = version, .. } | version /= tag -> do
Just Package{ location = Remote{..}, .. } | version /= tag -> do
echo $ "Found a newer tag for '" <> name <> "': " <> tag
let auth = GitHub.OAuth $ Encoding.encodeUtf8 token
owner' = GitHub.mkName Proxy "purescript"
Expand Down
6 changes: 3 additions & 3 deletions package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ library:
- text < 1.3
- Cabal
- turtle
- either
- filepath
- file-embed
- template-haskell
Expand All @@ -61,8 +62,7 @@ library:
- process
- network-uri
- versions
- lens
- lens-aeson
- lens-family-core
- safe
- fsnotify
- Glob
Expand Down Expand Up @@ -123,7 +123,7 @@ executables:
- async-pool
- process
- github
- lens
- lens-family-core
- stm
- vector
- temporary
Expand Down
Loading