Stream: ideas

Topic: roc init app scaffolding


view this post on Zulip Luke Boswell (May 20 2024 at 07:09):

Wanting to raise this issue #3139 for further discussion.

We talked about this briefly at SYCL, and I think this helps discovery of platforms, and also getting up and running quickly with a new application. I also think this would be a fun project for a new contributor to dive into, so writing this up with the intention to make a new "good first issue".

The proposal below can be upgraded when the future roc package index design is completed and provides a good starting point to validate some ideas before then.

Platform index. We create a new repository, e.g. roc-lang/temporary-platform-index that contains an index of platforms that are currently available. It could be as simple as a single flat file with the URLs.

Adding a new package. a PR against the repo. We can have a checklist to help guide platform authors. For example; we expect some documentation is available, prebuilt-binaries for supported targets, a init.roc plugin script for scaffolding a new app.

Fetching index. the cli subcommand roc init will fetch the latest version of the index file from GH servers (or maybe a cached version from roc-lang.org) and list the available platforms with a TUI interface. We can use a cached version if not available, though I think it's acceptable for now to check each time for a newer file, as the index should change infrequently and be easily cached.

Updating the index we could have a bot that runs once a week and creates a PR to update the index to the latest version/release of all the platforms, and/or remove platforms that are no longer available. I think it is acceptable to leave support for older versions so we can keep this simple for now.

Fuzzy search. Typing in the name of a platform, like roc init cli will fuzzy search and filter the list of platforms. For example, roc init cli would display https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br

Selecting a platform. the user can use up-down arrow keys to change their selection and when they press enter, the roc cli will scaffold out a new app that uses a release of the platform.

Metadata. use the a Raven package to provide metadata. For example we might want to store the following in the flat file instead of just a line separated list of URLs. For example, if we are currently on a arm64 mac machine and that target is not supported we can provide a helpful error message.

{
    name: "roc-lang/basic-cli",
    url: "https://github.com/roc-lang/basic-cli/releases/download/0.10.0/vNe6s9hWzoTZtFmNkvEICPErI9ptji_ySjicO6CkucY.tar.br",
    desc: "Write basic CLI apps",
    targets: [MacosArm64,MacosX64,LinuxArm64,LinuxX64,WindowsArm64,WindowsX64],
}

Scaffolding app structure. platform authors include a plugin script platform/init.roc which scaffolds out a new app. This should be located in the same folder as platform/main.roc alongside the prebuilt binaries. The roc cli provides a simple API main : { url : Str } -> List { name : Str, content : Str } where the url is provided so the script can use this to reference latest release. The script can import a URL package if there is a need use templated files. Future extension of this proposal could provide more information such as environment variables.

view this post on Zulip Agus Zubiaga (May 20 2024 at 15:01):

Minor note about the fuzzy search: The user should be able to change/refine the search term in the init TUI.

view this post on Zulip Luke Boswell (May 27 2024 at 02:21):

I'll update that Issue to track these changes. Let me know if your interested in implementing this. :smiley:

view this post on Zulip Ian McLerran (May 29 2024 at 16:39):

One question I have about this proposal: would the init.roc script maintained by the platform be required to accept an argument containing its own release URL? Since the script (I assume) would be included in the repo itself, the script could not possibly know its own Blake-3 hashed url.

view this post on Zulip Luke Boswell (May 29 2024 at 23:28):

That was the idea behind this API main : { url : Str } -> List { name : Str, content : Str }, though I'm not 100% if this is the best approach.

view this post on Zulip Luke Boswell (May 29 2024 at 23:30):

Also for future reference see the roc-start cli tool. This is a similar tool written using basic-cli.

view this post on Zulip Agus Zubiaga (May 30 2024 at 00:04):

I think we should come up with motivating examples if we want to go the script route, because copying a static folder might be enough and is simpler overall

view this post on Zulip Agus Zubiaga (May 30 2024 at 00:05):

Oh, I guess we do need it for the URL bit

view this post on Zulip Agus Zubiaga (May 30 2024 at 00:05):

Unless we have some kind of placeholder for that

view this post on Zulip Kiryl Dziamura (May 30 2024 at 02:26):

In the case of templates, we can have local path to the platform and substitute the url at roc-init time. This way the templates might be just examples in the platform repo.

I mean look at this - it’s already a template, you just need to copy it and replace the platform path. And you can also run it in the context of the platform repo.

What level of the flexibility for scaffolding we want? It would be easier to maintain/audit valid straightforward roc examples/templates that can be parsed and checked immediately rather than having a script that outputs text or ast.

However, simple copying might be not enough as different platforms might need very specific tools depending on their domain.

view this post on Zulip Luke Boswell (May 30 2024 at 03:27):

Another thing to consider. Is that to support surgical linking, the platform needs to provide at a minimum a stubbed app to compile to a dynamic library. Maybe there is some way we could unify these with a convention? I have been using app.roc in the root of the templates repositories for this, or for rust I made a libapp.roc just because cargo would name the library what I needed.

We could possibly have the init.roc plugin/script is what is used by the platform author to generate the stubbed app dynamic library thing for surgical linking, instead of having a standalone example. And this would ensure the init script is always correct.

view this post on Zulip Luke Boswell (May 30 2024 at 04:11):

Also, probably over complicating this

view this post on Zulip Robin Camarasa (Oct 30 2024 at 10:16):

Hi everyone, as mentioned in the new contributors channel I am interested in contributing to this topic ( https://roc.zulipchat.com/#narrow/channel/316715-contributing/topic/new.20contributors/near/479342332 ). @Sam Mohr mentioned that it would be good before jumping to implementation have some sort of plan which seems like a great idea.

Minimal viable product (MVP) requirements

Reading the different messages and comments in the issue and this conversation, I am tried to scaffold the requirements of an MVP: (This requirements are influenced by roc-start designed @Ian McLerran and previously mentioned by @Luke Boswell).

INFRASTRUCTURE SIDE:

UI SIDE:

THOUGHTS:

  1. where should the template files go? I see two options here: either in the platform index or in the platform repositories. Is there a consensus on this question? If this is on the platform repositories could this be included in the .tar.br file in the form of a template/ folder?
  2. Slightly off-topic and a noobie question but important for my understanding and future design choices, roc-start depends on gh is it the idea that all platform should be hosted on github?
  3. So far the requirements are only for the generation of applications but it should be generalized to the generation of platforms
  4. My idea would be to: revise the requirements of the MVP, agree upon it, improve the MVP upon incrementally by adding new features
  5. Is it better to have this discussion in zulip or in the GitHub issue?

I would appreciate some feedback as I am surely overlooking/misunderstanding many things and to be sure to start in the right direction.

view this post on Zulip Sam Mohr (Oct 30 2024 at 10:20):

Thanks for starting this discussion up! I'm going to bed now, but I can comment on this tomorrow

view this post on Zulip Robin Camarasa (Oct 30 2024 at 10:21):

Great good night!

view this post on Zulip Luke Boswell (Oct 30 2024 at 11:21):

where should the template files go?

The idea is that roc init loads a roc app (plugin) script that is provided by the platform author. That file might be called init.roc is in the platform and would be included in the platform package .tar.gz etc along with the other files.

The roc cli will then load that plugin and call it passing in the latest version string/url for that platform that is being scaffolded. The cli knows what the latest version is from the central index/list of packages.

The plugin uses this url, and possibly other imported packages, to provide back a list of files (file name, and file contents) which the roc cli then copies into the new directory.

view this post on Zulip Luke Boswell (Oct 30 2024 at 11:22):

idea that all platform should be hosted on github?

No, this shouldn't be necessary. A roc package (e.g. including a platform package) can be hosted at any URL.

view this post on Zulip Luke Boswell (Oct 30 2024 at 11:23):

  1. Is it better to have this discussion in zulip or in the GitHub issue?

I think zulip is better for discussion when scoping ideas/proposals. GH is better during the implementation.

view this post on Zulip Robin Camarasa (Oct 30 2024 at 12:12):

Thanks for clarifying, I understand much better now. Then I believe that good first steps would be to make a mock-up platform with an init.roc file and a mock-up index repository that references to that platform. Once I have this running I could implement roc init --platform [PLATFORM] [LOCATION] and after that the TUI part. It might take me sometimes though as I have never implemented platforms before, but that's fun!

Based on your previous messages I take as a working hypothesis that the init.roc would have a main function with the following signature main : { url : Str } -> List { name : Str, content : Str }.

I believe that I have what I need to get started. I will keep you posted on this channel of my questions and advances. In the mean time I am open to remarks and guidance :smile:

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:24):

awesome, thanks for getting this moving!

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:24):

I think making an index is blocked on #ideas > package naming and search

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:25):

we don't know how the names should work yet, and there are a lot of tradeoffs there

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:25):

which also influence how the index would work

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:25):

that said, I think this part is totally unblocked:

roc init --platform https://...

(as long as it's taking a direct URL to the platform, since we already support that today!)

view this post on Zulip Robin Camarasa (Oct 30 2024 at 13:47):

Great I will start with roc init --platform https://... and probably also support roc init --platform file://... . I understand that indexing packages might need more engineering :smile:

view this post on Zulip Robin Camarasa (Oct 30 2024 at 13:47):

For now I focuss on how to implement a platform following the Go example of the website https://github.com/roc-lang/examples/tree/main/examples/GoPlatform

view this post on Zulip Richard Feldman (Oct 30 2024 at 13:51):

awesome, thank you so much!

view this post on Zulip Luke Boswell (Oct 30 2024 at 19:00):

The best example for a plugin here is the roc glue subcommand which does something similar but that generates souce code for interfacing with roc.

view this post on Zulip Luke Boswell (Oct 30 2024 at 19:01):

The platform files are here https://github.com/roc-lang/roc/tree/main/crates/glue/src

view this post on Zulip Luke Boswell (Oct 30 2024 at 19:02):

And entry from the cli is here https://github.com/roc-lang/roc/blob/69dd8d77f3127cb21eaa34f8c7533930e30b923a/crates/cli/src/main.rs#L116

view this post on Zulip Robin Camarasa (Oct 31 2024 at 06:28):

Thanks that helps a lot. Something I wondered about yesterday is retro-compatibility. Should we support a platform without an init.roc file?

view this post on Zulip Luke Boswell (Oct 31 2024 at 06:35):

I'm not sure how we would do that. I can't imagine what we would put in... maybe just a blank app module header with the version? So something like this...

app [] { pf: platform "<PLATFORM URL>" }

view this post on Zulip Robin Camarasa (Nov 06 2024 at 09:26):

Progress report: 2024-11-06

I can only work on the ROC project on Wednesdays (my part time day) and I thought that it would be good to update you every week about my progress on the feature. I believe that this will help getting feedback, however if you consider this spamming (or in the wrong channel) let me know and I will adapt my communication.

Done

Next step

thread 'main' panicked at crates/packaging/src/tarball.rs:279:9:
not yet implemented
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::panicking::panic
   3: roc_packaging::tarball::read_header
   4: roc_packaging::tarball::add_source_files
   5: roc_packaging::tarball::build
   6: roc_cli::build
   7: roc::main

Ideas along the way

view this post on Zulip Luke Boswell (Nov 06 2024 at 10:23):

Love the idea of giving an update. :grinning:

view this post on Zulip Robin Camarasa (Nov 10 2024 at 13:57):

Progress report: 2024-11-10

Previously done

Previous ideas along the way

Done

Next steps

Ideas along the way

view this post on Zulip Sam Mohr (Nov 10 2024 at 15:29):

@Robin Camarasa just curious, is your goal to write a Roc version of the roc init subcommand?

view this post on Zulip Sam Mohr (Nov 10 2024 at 15:29):

Maybe I'm missing something, but I'd say a compiler feature like this should be integrated into the Rust code that's already present

view this post on Zulip Robin Camarasa (Nov 10 2024 at 16:44):

Hi @Sam Mohr, I probably did not make myself clear enough . I am working on a fork of the repo of the roc compiler and writing everything in Rust. Once it's ready I will make a pull request. Does that clear things out?

view this post on Zulip Luke Boswell (Nov 10 2024 at 20:46):

@Robin Camarasa pretty much everything you need is in the roc glue subcommand, and you cant find the entrypoint here;

https://github.com/roc-lang/roc/blob/b7c2cb084e15a56320e652ad3c77fdb8262bc1a4/crates/glue/src/load.rs#L38

So you could copy paste that, remove all the glue/Types related stuff and "call" the init.roc main to see what files the platform needs generated.

view this post on Zulip Luke Boswell (Nov 10 2024 at 20:48):

Roc cli will load the init.roc and build that roc app into a dynamic library, then load that and call it to see what files the plugin from the platform wants generated.

view this post on Zulip Robin Camarasa (Nov 11 2024 at 06:35):

Oh yes indeed you already mentioned it before but I kind of forgot about it. I will explore glue! Thanks!

view this post on Zulip Robin Camarasa (Nov 20 2024 at 11:31):

Progress report: 2024-11-20

Done

Blocking point / Question

main : Str -> List { name : Str, content : Str }
main = \platform ->
[{ name : "app.roc", content: "app [main] { pf: platform \"$(platform)\" }\n\n# Can segfault on some Ubuntu 20.04 CI machines, see #164.\nmain = \"Roc <3 Go!\"\n" }]
LoadingProblem(FormattedReport("\u{1b}[1;36m── MISSING HEADER in scratch/test_platform/init.roc ────────────────────────────\u{1b}[0m\n\nI am expecting a header, but got stuck here:\n\n\u{1b}[1;36m1\u{1b}[0m\u{1b}[1;36m│\u{1b}[0m  \u{1b}[37mmain = \\args ->\u{1b}[0m\n    \u{1b}[1;31m^\u{1b}[0m\n\nI am expecting a module keyword next, one of \u{1b}[1;32minterface\u{1b}[0m, \u{1b}[1;32mapp\u{1b}[0m, \u{1b}[1;32mpackage\u{1b}[0m\nor \u{1b}[1;32mplatform\u{1b}[0m."))

Previously done

Previous ideas along the way

view this post on Zulip Anton (Nov 20 2024 at 12:51):

Is it the idea then that the init.roc should be an application?

Maybe, I'm not sure what @Luke Boswell had in mind for the plugin like behavior

view this post on Zulip Luke Boswell (Nov 20 2024 at 20:27):

Is it the idea then that the init.roc should be an application?

Yes this is the idea.

view this post on Zulip Luke Boswell (Nov 20 2024 at 20:27):

Similar to how RustGlue.roc is an app.


Last updated: Jun 16 2026 at 16:19 UTC