Skip to content

Commit

Permalink
Add hello command (#114)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmattio authored Jun 4, 2021
1 parent 485a332 commit 5aad207
Show file tree
Hide file tree
Showing 26 changed files with 514 additions and 3 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Added

- Added an `hello` command to generate a tutorial project
- Added a `parse_binaries` stanza that can be `true` to force Spin to parse binary files
- Added a `raw_files` stanza that takes a list of file or glob expressions to instruct Spin to copy files instead of parsing them
- Added a new `c-bindings` template for C bindings using `ctypes`
Expand Down
67 changes: 67 additions & 0 deletions bin/commands/cmd_hello.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
open Spin

let run ~path =
let open Result.Syntax in
let path = Option.value path ~default:Filename.current_dir_name in
let* () =
try
match Sys.readdir path with
| [||] ->
Ok ()
| _ ->
Error
(Spin_error.failed_to_generate "The output directory is not empty.")
with
| Sys_error _ ->
Sys.mkdir_p path;
Ok ()
in
try
let* template = Template.read (Template.Official Spin_template.hello) in
Template.generate ~path template
with
| Sys.Break | Failure _ ->
exit 1
| e ->
raise e

(* Command line interface *)

open Cmdliner

let doc = "Generate a tutorial project in the given directory"

let sdocs = Manpage.s_common_options

let exits = Common.exits

let envs = Common.envs

let man_xrefs = [ `Main; `Cmd "new" ]

let man =
[ `S Manpage.s_description
; `P
"$(tname) generates a tutorial project. This is useful if this is your \
first project with OCaml and you want to learn by example."
; `P
"If you are already familiar with the typical OCaml development \
environment, use spin-new(1) instead."
]

let info = Term.info "hello" ~doc ~sdocs ~exits ~envs ~man ~man_xrefs

let term =
let open Common.Syntax in
let+ _term = Common.term
and+ path =
let doc =
"The path where the project will be generated. If absent, the project \
will be generated in the current working directory."
in
let docv = "PATH" in
Arg.(value & pos 0 (some string) None & info [] ~doc ~docv)
in
run ~path |> Common.handle_errors

let cmd = term, info
1 change: 0 additions & 1 deletion bin/commands/cmd_new.ml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ let run ~ignore_config ~use_defaults ~template ~path =
in
match Template.source_of_string template with
| Some source ->
let open Result.Syntax in
(try
let* template = Template.read ?context ~use_defaults source in
Template.generate ~path template
Expand Down
3 changes: 2 additions & 1 deletion bin/main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ open Cmdliner

let () = Printexc.record_backtrace true

let cmds = [ Cmd_config.cmd; Cmd_ls.cmd; Cmd_new.cmd ]
let cmds = [ Cmd_config.cmd; Cmd_ls.cmd; Cmd_new.cmd; Cmd_hello.cmd ]

let run () =
let message =
Expand All @@ -16,6 +16,7 @@ Available Commands:
config Update the current user's configuration
ls List the official templates
new Generate a new project from a template
hello Generate the tutorial project

Useful options:
--help Show manual page
Expand Down
2 changes: 1 addition & 1 deletion script/demo-record.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ cd "$TEMP_DIR"

asciinema rec -c "$DIR/demo-emulate.sh"

# cat /var/folders/1k/w8wtfpk909s_mvn_72q6d2p40000gn/T/tmpl3vpup57-ascii.cast | svg-term --out "doc/demo.svg" --window --no-cursor --width 80 --height 24
# cat /var/folders/1k/w8wtfpk909s_mvn_72q6d2p40000gn/T/tmp8dhvupt4-ascii.cast | svg-term --out "doc/demo.svg" --window --no-cursor --width 80 --height 24
8 changes: 8 additions & 0 deletions template/dune
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,11 @@
(source_tree js)))
(action
(run %{bin:ocaml-crunch} -m plain js -o %{targets})))

(rule
(targets hello.ml)
(deps
(:data
(source_tree hello)))
(action
(run %{bin:ocaml-crunch} -m plain hello -o %{targets})))
7 changes: 7 additions & 0 deletions template/hello/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# bin

Native project containing a binary.

```bash
spin new bin
```
15 changes: 15 additions & 0 deletions template/hello/spin
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
(name hello)

(description "Tutorial template without any configuration")

(post_gen
(actions
(run make deps)
(run make build))
(message "🎁 Installing packages globally. This might take a couple minutes."))

(example_commands
(commands
("make deps" "Download runtime and development dependencies.")
("make build" "Build the dependencies and the project.")
("make test" "Starts the test runner.")))
9 changes: 9 additions & 0 deletions template/hello/template/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Dune generated files
_build/
*.install

# Merlin configuring file for Vim and Emacs
.merlin

# Local OPAM switch
_opam/
9 changes: 9 additions & 0 deletions template/hello/template/.ocamlformat
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Pin the version of ocamlformat. The formatting will fail if a version other than 0.18.0 is used.
# This ensures that the formatting does not depend on the specific version of ocamlformat developers use.
version = 0.18.0
# The conventional profile is fairly standard, but you can also try `sparse` or `janestreet`.
profile = conventional
# Format the code source found in docstrings
parse-docstrings = true
# Insert break lines for docstring that are longer than 80 characters.
wrap-comments = true
15 changes: 15 additions & 0 deletions template/hello/template/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
ISC License

Copyright (c) 2021 Your name

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
77 changes: 77 additions & 0 deletions template/hello/template/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# This Makefile offers simpler frontend to the different tools for common development tasks.
# You'll see that all of the commands are prepended by `opam exec -- ...` to run use the
# tools installed in your Opam switch without having to run `eval $(opam env)`
.DEFAULT_GOAL := all

ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
$(eval $(ARGS):;@:)

.PHONY: all
all:
opam exec -- dune build --root . @install

.PHONY: deps
deps: ## Install development dependencies
opam install -y dune-release ocamlformat utop ocaml-lsp-server
opam install --deps-only --with-test --with-doc -y .

.PHONY: create_switch
create_switch: ## Create an opam switch without any dependency
opam switch create . --no-install

.PHONY: switch
switch: ## Create an opam switch and install development dependencies
opam install . --deps-only --with-doc --with-test
opam install -y dune-release ocamlformat utop ocaml-lsp-server

.PHONY: lock
lock: ## Generate a lock file
opam lock -y .

.PHONY: build
build: ## Build the project, including non installable libraries and executables
opam exec -- dune build --root .

.PHONY: install
install: all ## Install the packages on the system
opam exec -- dune install --root .

.PHONY: start
start: all ## Run the produced executable
opam exec -- dune exec --root . bin/main.exe $(ARGS)

.PHONY: test
test: ## Run the unit tests
opam exec -- dune runtest --root .

.PHONY: clean
clean: ## Clean build artifacts and other generated files
opam exec -- dune clean --root .

.PHONY: doc
doc: ## Generate odoc documentation
opam exec -- dune build --root . @doc

.PHONY: servedoc
servedoc: doc ## Open odoc documentation with default web browser
open _build/default/_doc/_html/index.html

.PHONY: fmt
fmt: ## Format the codebase with ocamlformat
opam exec -- dune build --root . --auto-promote @fmt

.PHONY: watch
watch: ## Watch for the filesystem and rebuild on every change
opam exec -- dune build --root . --watch

.PHONY: utop
utop: ## Run a REPL and link with the project's libraries
opam exec -- dune utop --root . lib -- -implicit-bindings

.PHONY: release
release: all ## Run the release script
opam exec -- dune-release tag
opam exec -- dune-release distrib
opam exec -- dune-release publish distrib -y
opam exec -- dune-release opam pkg
opam exec -- dune-release opam submit --no-auto-open -y
89 changes: 89 additions & 0 deletions template/hello/template/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Hello

This project serves as a tutorial for your first OCaml project.

It will guide you through the typical project structure and OCaml development workflow.
Although the organisation and tools used by the community vary, the ones used here are fairly standard and are the recommended way to work with OCaml with the [OCaml Platform](https://ocaml.org/platform/).

If you are already familiar with the setup and are looking to start a new project, you should probably use one of Spin's official template (list them with `spin ls`).

## Setup your development environment

You need Opam, you can install it by following [Opam's documentation](https://opam.ocaml.org/doc/Install.html).

With Opam installed, you can install the dependencies in a new local switch with:

```bash
make switch
```

Or globally, with:

```bash
make deps
```

Both of these commands will install the tools you typically need for you IDE (e.g. `ocaml-lsp-server`, `ocamlformat`).
Once the installation is complete, you can open the project in your IDE with the `vscode-ocaml-platform` extension.

Finally, build the project with:

```bash
make build
```

### Running Binary

After building the project, you can run the main binary that is produced.

```bash
make start
```

### Running Tests

You can run the test compiled executable:

```bash
make test
```

### Building documentation

Documentation for the libraries in the project can be generated with:

```bash
make doc
make servedoc
```

### Project Structure

The following snippet describes the project structure.

```text
.
├── bin/
| Source for the executable. This links to the library defined in `lib/`.
├── lib/
| Source for library of the project.
├── test/
| Unit tests and integration tests.
├── dune-project
| Dune file used to mark the root of the project and define project-wide parameters.
| For the documentation of the syntax, see https://dune.readthedocs.io/en/stable/dune-files.html#dune-project
├── LICENSE
├── Makefile
| Make file containing common development command.
├── README.md
└── hello.opam
Opam package definition.
To know more about creating and publishing opam packages, see https://opam.ocaml.org/doc/Packaging.html.
```
10 changes: 10 additions & 0 deletions template/hello/template/bin/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
(executable
; The name of th executable.
; This is only the development name, but if user install the package, it will
; be accessible with the name defined in `public_name`
(name main)
(public_name hello)
; The executable depends on the library defined in `lib/`.
; This make the module `Hello` and its exposed functions available in
; all of the modules in this directory.
(libraries hello))
3 changes: 3 additions & 0 deletions template/hello/template/bin/main.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
let () =
let greeting = Hello.greet "world" in
print_endline greeting
4 changes: 4 additions & 0 deletions template/hello/template/bin/main.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
(** Main entry point for our application.
This is left empty intentionnally, because executables should not have any
interfaces. *)
11 changes: 11 additions & 0 deletions template/hello/template/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
; This defines some global environment configuration for Dune.
; Here, we add some compiler flags in development to add warnings
; on compilation, and fail the compilation when there are warnings.
; If you want to deactivate some warning or error, you can add them
; here, for instance `-w +A-48-42-44-4` will deactivate warning 4 in
; addition to the ones already listed.

(env
(dev
(flags
(:standard -w +A-48-42-44 -warn-error +A-3))))
Loading

0 comments on commit 5aad207

Please sign in to comment.