Giter Club home page Giter Club logo

purenix's People

Contributors

cdepillabout avatar jonascarpay avatar yvan-sraka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

purenix's Issues

implement bundle command

purs and spago both implement a bundle command.

This command bundles all the output .js files for each PureScript module into a single .js. This single .js file is easy to deploy or copy somewhere else.

It may make sense for us to also implement a bundle command in purenix. This command would output a single .nix for the entire project. This single .nix file would be easy to copy to another project (or possibly even use in a larger repo like Nixpkgs).

We need to investigate exactly how the bundle command works in purs and spago. We need to come up with a good way of including all our output Nix code into a single file.

This was mentioned in #22 (comment).

(Optionally) delete non-nix files

Currently, purenix will only create new files. Maybe it's a good idea to also delete the json files once we're done with them, to leave the directory in as clean a state as possible? AFAICT that's what the JS backend does too.

Support running/evaluating built functions

Spago assumes a backed has a --run Module.Name.function flag that will execute the given function. This is also how tests are implemented. I think the following snippet is a reasonable implementation for --run in purenix.

mkdir tmp-nix
export NIX_STORE_PATH=$(pwd)/tmp-nix/store
export NIX_DATA_DIR=$(pwd)/tmp-nix/share
export NIX_LOG_DIR=$(pwd)/tmp-nix/log/nix
export NIX_STATE_DIR=$(pwd)/tmp-nix/log/nix
nix-instantiate --eval --readonly-mode -E "let module = import ./output/Test.Main; in module.main null"

This would of course be implemented within Haskell and the module to import as well as the function to evaluate is defined by the flag.

The snippet runs evaluation against a temporary nix store and in readonly-mode so it should be fine run inside a nix build. I've only tested that it does indeed run in the simplest of scenarios so far.

make sure that an FFI file exists if a PureScript module has foreign imports

Current in purenix, we copy over an FFI file like Main.nix to output/Main/foreign.nix, but only if Main.nix exists.

We don't have any check for the situation where Main.purs uses FFI functions, but no Main.nix FFI file exists. We should probably add this check, since it can be easy to forget to write an FFI file.

Rename modules

We might want to also change our module Lib to be named something more descriptive.

I guess we could also change modules like Nix.Convert and Nix.Expr to something like PureNix.Convert and PureNix.Expr, but I don't feel as strongly about this.

Originally posted by @cdepillabout in #10 (comment)

Quick Start Broken?

Hey, I was trying to follow the Quick Start but couldn't get the example to build. After following the steps, including switching out the package set hash to the latest on master of the temp-package-set repo. Running spago build after that complained that that package set required an older version of purs (0.14.something), but I chose the option to override it in the packages.dhall file..

The result of running spago build was that modules compiled to CoreFn but purenix failed:

[info] Build succeeded.
purenix: impossible
CallStack (from HasCallStack):
  error, called at src/PureNix/Identifiers.hs:63:30 in purenix-1.1-AKRNnyJSalY6yydb60EpDF:PureNix.Identifiers
[error] Backend "purenix" exited with error:1

Are you able to reproduce this? FWIW I also tried to build a custom nix shell using EasyPurescriptNix with the appropriate version of purs that spago wanted for that package set, and I still got errors, albeit a different one. Something about not finding sourcePos.

This is my first rodeo trying to use a different PureScript backend, and I'm not a nix power user so maybe I'm just missing something 🤔

characters in quotes aren't escaped correctly

It looks like some characters in quotes aren't escaped correctly.

I haven't extensively tested this, but here is one example I've found:

module Main where

example :: String
example = "\""

This compiles to:

let
  module = { };
  example = """;
in
  {inherit example;}

But example should probably be "\"".

README

We need a README.

  • introduction
    • motivation
  • usage
    • spago
    • FFI/prelude
    • notes on laziness
  • generated code samples

create `purescript-nix-buitins` library

It would be nice to have a library like purescript-nix-builtins that provides FFI for all the different Nix builtins (like builtins.deepSeq, builtins.getEnv, builtins.mapAttrs, etc). This library should also provide FFI data types for types from Nix that are not available from PureScript by default. For instance, a Path type to represent Nix paths.

A couple other points:

laziness

We decided to move forward and make purenix a lazy language.

The big downside of this is that we will have to be careful when copying (JavaScript) PureScript code, since it is strict. Our Prelude and other standard libraries will have to be built from the ground up around laziness.

One concern is whether there is some sort of compilation step in purs before the CoreFn output phase that makes use of PureScript being a strict language. This would cause problems for us. At some point we should probably ask the PureScript developers if they know of anywhere this could bite us.

core library support

This issue is to track which core libraries have been ported to PureNix.

Done

These are libraries that have already been ported.

Todo

These are libraries that still need to be ported.

Won't Do / Can't Do

These are libraries that either can't be ported to PureNix, or don't make sense to port to PureNix.

  • assert

    Nix does have an assert statement, but I'm not sure it would be able to be used with a similar API to purescript-assert. Creating a purescript-nix-assert library would likely be better.

  • console

    Nix doesn't have any way of writing arbitrary text to the console. There is the builtins.trace Nix function, but that could be wrapped up in it's own library.

  • docs-search

    I'm not sure what this is or how it would be related to PureNix.

  • effect

    Nix doesn't have any way of doing arbitrary effects. In theory, we could have an Effect type for compatibility, but in practice we wouldn't be able to do anything interesting with it.

    edit: There was a little discussion in purenix-org/temp-package-set#1 as to whether or not purescript-effect would make sense for PureNix. There are a couple good points in favor of having purescript-effect.

  • exceptions

    Nix doesn't really have exceptions the same way JavaScript does. Nix does have the builtins.abort, assert, and builtins.tryEval functions, which may be able to be wrapped up in a nice library.

  • gen

    See the problem with random.

  • minibench

    I don't think Nix has any way of getting the current time (or at least to any precision that would be necessary for benchmarking).

  • parallel

    Nix doesn't have any built-in way of running computations in parallel. It is possible we could support this same API in PureNix for compatibility, but it is likely we would only be able to run the computations sequentially.

  • quickcheck

    See the problem with random.

  • random

    As far as I know, Nix doesn't have any sort of random number generator. There is no way to generate random numbers.

    edit: Thinking about this a little more, we could have purescript-random be a pseudorandom number generator (PRNG). All the random functions could just take a seed that has to be passed in. The seed would be the initial seed for the PRNG. This could be useful for people that are willing to pass in a random seed when calling nix-build. This seems like a reasonable way to use libraries like purescript-random, purescript-gen, and purescript-quickcheck.

  • refs

    Nix doesn't have any way of mutating values, so refs are not possible.

  • tailrec

    Nix is lazy, so this sort of trampolining isn't necessary.

Implementing the `callPackage` pattern with PureNix

Hello,

Thanks for this great project! I'm looking to better understand what is possible or not to do with Nix PureScrip backend, and mainly how we might replicate the callPackage pattern? I looked a bit over the internet, without success, about how to write a Nix package, a NixOS option or configuration using PureNix, before trying to hack on that myself. Are you aware of existing examples or discussions about this? If not, are there any known challenges or obstacles in doing so?

Thanks!

On a side note: Is there a way to structure PureNix's output, output/Main/default.nix, so that it aligns with the flakes' syntax?

Make a release

At some point, we'll have to do a release. Tentative checklist:

decide what to do about interpolation characters in strings

Right now, we don't check whether PureScript strings have Nix interpolation characters.

For example, this PureScript code:

myTest :: String -> String
myTest hello = "${hello}"

currently becomes:

let
  myIdent = hello: "${hello}";
  ...

We should decide what to do about this.

Our two choices are:

  1. Do nothing and just make sure that users are aware of the need to escape a ${ sequence when writing literal strings.
  2. Actively escape those sequences in strings in purenix. We could possibly add our own newtype StringWithInterp = StringWithInterp String newtype wrapper that purenix is aware of and doesn't do escaping on.

test suite

It would be nice to have a test-suite for purenix.

The most important tests would be for the Nix.Convert and Nix.Print modules.

We'd also especially like to test that all our identifiers, strings, and attrset keys get escaped correctly.

Places to pull ideas from:

As of this writing, neither purerl nor purescript-native have a test suite.

create a real package set

In order for PureNix to be widely usable, we need a real package set for people to depend on.

I have a temporary package set that I've been using while doing development on the core libraries: https://github.com/purenix-org/temp-package-set. But this pins all packages to the master branch instead of a release tag.

We need a real package set where everything is correctly pinned to a release tag, like the upstream normal PureScript Package Sets. It would be nice to also have all of their CI automation.

Also, before deciding to copy the PureScript Package Set approach, we should take a look at the PureScript Registry and see if it would be possible to use that, since that is what the PureScript community will use going forward (not the PureScript Package Sets). We need to ask the PureScript Registry maintainers if the registry is directly usable by alternative backends.

If anyone is interested in putting this together, please leave a comment and I can create any repos necessary for you to get started setting this up.

add binary cache

Just loading the devShell and it needs to build a lot of stuff.
I see there is already a cachix github action but commented out. Maybe consider re-adding it?

Clean up conversion output

I imagine we might want to get rid of this line, since purs doesn't output something like this. Also, for big repos it will sometimes output so many lines that the important Warning lines will be scrolled off the screen.

Originally posted by @cdepillabout in #16 (comment)

don't run purenix for corefn.json files that are older than the output default.nix file

Right now, when you run purenix, it looks for all the output/*/corefn.json files, and transpiles each of them to output/*/default.nix.

It may be possible to instead check if an output/*/default.nix file is newer than output/*/corefn.json, and not regenerate the output/*/default.nix in that case.

We should confirm that purs has similar functionality, and doesn't touch the corefn.json file when it is already newer than the input src/*.purs input file.

There was a little discussion about this in #22 (comment).

"'allow-import-from-derivation' is disabled" error

I'm new to nix, so I don't know if this is an error or intended, but when I try to run nix flake show,
I get the error 'allow-import-from-derivation' is disabled.

$ nix flake show --version
nix (Nix) 2.4
$ nix flake show --show-trace
git+file:///.../github/purenix?ref=main&rev=4dd6ec3913825a66cc2c8a82219428d812c0a203
├───defaultPackage
error: cannot build '/nix/store/vnvd0kq9vphs2b191yh0wk1z7ffffjlq-cabal2nix-purenix.drv' during evaluation because the option 'allow-import-from-derivation' is disabled

       … while importing '/nix/store/ybyh4wwhkwg6fpp2acqd87rkrhj4499r-cabal2nix-purenix'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:87:47:

           86|       # info that callPackage uses to determine the arguments).
           87|       drv = if lib.isFunction fn then fn else import fn;
             |                                               ^
           88|       auto = builtins.intersectAttrs (lib.functionArgs drv) scope;

       … while evaluating 'drvScope'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:91:18:

           90|       # this wraps the `drv` function to add a `overrideScope` function to the result.
           91|       drvScope = allArgs: drv allArgs // {
             |                  ^
           92|         overrideScope = f:

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/lib/customisation.nix:69:16:

           68|     let
           69|       result = f origArgs;
             |                ^
           70|

       … while evaluating 'makeOverridable'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/lib/customisation.nix:67:24:

           66|   */
           67|   makeOverridable = f: origArgs:
             |                        ^
           68|     let

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:101:8:

          100|       };
          101|     in lib.makeOverridable drvScope (auto // manualArgs);
             |        ^
          102|

       … while evaluating 'callPackageWithScope'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:78:37:

           77|   # here `bar` is a manual argument.
           78|   callPackageWithScope = scope: fn: manualArgs:
             |                                     ^
           79|     let

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:118:28:

          117|   defaultScope = mkScope self;
          118|   callPackage = drv: args: callPackageWithScope defaultScope drv args;
             |                            ^
          119|

       … while evaluating 'callPackage'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:118:22:

          117|   defaultScope = mkScope self;
          118|   callPackage = drv: args: callPackageWithScope defaultScope drv args;
             |                      ^
          119|

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:174:9:

          173|       };
          174|     }) (self.callPackage src args);
             |         ^
          175|

       … while evaluating 'overrideCabal'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/lib/compose.nix:38:22:

           37|    */
           38|   overrideCabal = f: drv: (drv.override (args: args // {
             |                      ^
           39|     mkDerivation = drv: (args.mkDerivation drv).override f;

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:162:5:

          161|   callPackageKeepDeriver = src: args:
          162|     overrideCabal (orig: {
             |     ^
          163|       preConfigure = ''

       … while evaluating 'callPackageKeepDeriver'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:161:33:

          160|   # annoyance.
          161|   callPackageKeepDeriver = src: args:
             |                                 ^
          162|     overrideCabal (orig: {

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:218:14:

          217|            inherit src;
          218|          }) (callPackageKeepDeriver expr args);
             |              ^
          219|

       … while evaluating 'overrideCabal'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/lib/compose.nix:38:22:

           37|    */
           38|   overrideCabal = f: drv: (drv.override (args: args // {
             |                      ^
           39|     mkDerivation = drv: (args.mkDerivation drv).override f;

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:216:10:

          215|         };
          216|       in overrideCabal (orig: {
             |          ^
          217|            inherit src;

       … while evaluating 'callCabal2nixWithOptions'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:205:66:

          204|     # Creates a Haskell package from a source package by calling cabal2nix on the source.
          205|     callCabal2nixWithOptions = name: src: extraCabal2nixOptions: args:
             |                                                                  ^
          206|       let

       … from call site

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:220:38:

          219|
          220|     callCabal2nix = name: src: args: self.callCabal2nixWithOptions name src "" args;
             |                                      ^
          221|

       … while evaluating 'callCabal2nix'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/make-package-set.nix:220:32:

          219|
          220|     callCabal2nix = name: src: args: self.callCabal2nixWithOptions name src "" args;
             |                                ^
          221|

       … from call site

       at /nix/store/lgkd30fbvyz9ndyqai6c2cckbfp12bfc-source/nix/overlay.nix:33:11:

           32|           in
           33|           hfinal.callCabal2nix "purenix" src { };
             |           ^
           34|       };

       … while evaluating the attribute 'haskellPackages.purenix'

       at /nix/store/lgkd30fbvyz9ndyqai6c2cckbfp12bfc-source/nix/overlay.nix:5:9:

            4|       prev.haskell.packageOverrides hfinal hprev // {
            5|         purenix =
             |         ^
            6|           let

       … while evaluating 'overrideCabal'

       at /nix/store/r85b90gdvvpfl04rnn2aisr6jggi2pp0-source/pkgs/development/haskell-modules/lib/compose.nix:38:22:

           37|    */
           38|   overrideCabal = f: drv: (drv.override (args: args // {
             |                      ^
           39|     mkDerivation = drv: (args.mkDerivation drv).override f;

       … from call site

       at /nix/store/lgkd30fbvyz9ndyqai6c2cckbfp12bfc-source/nix/overlay.nix:38:5:

           37|   purenix =
           38|     final.haskell.lib.compose.justStaticExecutables final.haskellPackages.purenix;
             |     ^
           39|

       … while evaluating the attribute 'purenix'

       at /nix/store/lgkd30fbvyz9ndyqai6c2cckbfp12bfc-source/nix/overlay.nix:37:3:

           36|
           37|   purenix =
             |   ^
           38|     final.haskell.lib.compose.justStaticExecutables final.haskellPackages.purenix;

       … while evaluating the attribute 'defaultPackage'

       at /nix/store/lgkd30fbvyz9ndyqai6c2cckbfp12bfc-source/flake.nix:15:11:

           14|         {
           15|           defaultPackage = pkgs.purenix;
             |           ^
           16|           packages.purenix = pkgs.purenix;

add support for running tests with `spago test`

Spago has a test command that makes it easy to run tests. PureNix probably needs something added to be able to work with spago test.

This hasn't really been a problem up until now, since none of the PureNix libraries have tests. But now there is a tasty-like testing framework for PureNix (https://github.com/thought2/purescript-miraculix by @thought2), so it would be really convenient to be able to run tests directly with spago test.

Someone interested in implementing this may want to do the following:

  • Investigate the Spago codebase to find out exactly what it does when running spago test.

    I imagine this function is a good place to start: https://github.com/purescript/spago/blob/aa7c0de6d903262f69452663c09fad9c441af8d3/src/Spago/Build.hs#L241-L256

    Keep in mind that it is quite possible there are two different code-paths here, one for the normal JS backend and one for alternative backends (like PureNix).

    It would be great if you could leave a comment on this issue with exactly what you figured out.

  • Optionally go on the PureScript Discord and ask in #compiler or #purerl how the Erlang backend handles spago test. They may have some good suggestions.

  • Decide on how PureNix should handle spago test, and leave a short comment here with how you see this working.

  • Send a PR implementing whatever is necessary.

Naming convention for purenix libraries.

I noticed that the ports of the 'official' PS packages still keep the same names of their origins.

E.g. purescript-nonempty

Would it maybe make sense to name them either purescript-nix-nonempty or even purenix-nonempty. I think the purescript- prefix is a leftover from bower times. It's not mandatory for spago anymore?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.