forked from ocaml/dune
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Towards completion of ocaml#159 Signed-off-by: Shon Feder <[email protected]>
- Loading branch information
Showing
5 changed files
with
226 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
open! Stdune | ||
open! Import | ||
|
||
module Kind = struct | ||
type t = | ||
| Library | ||
| Executable | ||
|
||
let to_string = function | ||
| Library -> "library" | ||
| Executable -> "executable" | ||
end | ||
|
||
module File = struct | ||
type t = | ||
{ path: Path.t | ||
; name: string | ||
; content: string } | ||
|
||
let make path name content = | ||
{path; name; content} | ||
|
||
let full_path {path; name; _} = | ||
Path.relative path name | ||
|
||
let create file = | ||
let path = full_path file in | ||
if Path.exists path then | ||
Error path | ||
else | ||
Ok (Io.write_file ~binary:false path file.content) | ||
end | ||
|
||
module Init_context = struct | ||
type t = | ||
{ kind : Kind.t | ||
; pname : string | ||
; dir : Path.t } | ||
|
||
let make pname kind path = | ||
let dir = | ||
match path with | ||
| None -> Path.of_filename_relative_to_initial_cwd pname | ||
| Some path -> | ||
if Filename.is_relative path then | ||
Path.of_filename_relative_to_initial_cwd path | ||
else | ||
Path.of_string path | ||
in | ||
{kind; pname; dir} | ||
end | ||
|
||
module Project_dir = struct | ||
type t = | ||
{ dir : Path.t | ||
; files : File.t list } | ||
|
||
let root (c : Init_context.t) = | ||
let package_opam = | ||
let name = Printf.sprintf "%s.opam" c.pname in | ||
File.make c.dir name "" | ||
in | ||
{dir = c.dir; files = [package_opam]} | ||
|
||
let lib (c : Init_context.t) = | ||
let dir = Path.relative c.dir "src" in | ||
let lib_dune = | ||
let name = "dune" in | ||
let content = Printf.sprintf "\ | ||
;; Uncomment stanzas to include their functionality | ||
(library | ||
(name %s) | ||
(public_name %s) | ||
;; (inline_tests) | ||
;; (libraries core) | ||
;; (preprocess (pps ppx_inline_test)) | ||
) | ||
" c.pname c.pname | ||
in | ||
File.make dir name content | ||
in | ||
{dir; files = [lib_dune]} | ||
|
||
let bin (c : Init_context.t) = | ||
let dir = Path.relative c.dir "bin" in | ||
let make_file = File.make dir | ||
in | ||
let bin_dune = | ||
let name = "dune" in | ||
let content = Printf.sprintf "\ | ||
(executable | ||
(public_name %s) | ||
(name main) | ||
(libraries %s)) | ||
" c.pname c.pname | ||
in | ||
make_file name content | ||
in | ||
let bin_ml = | ||
let name = "main.ml" in | ||
let content = Printf.sprintf "let () = print_endline \"Hello, World!\"\n" in | ||
make_file name content | ||
in | ||
let files = [bin_dune; bin_ml] | ||
in | ||
{dir; files} | ||
|
||
let create_dir t = | ||
try Path.mkdir_p t.dir with | ||
| Unix.Unix_error (EACCES, _, _) -> | ||
Exn.fatalf "A project directory cannot be created: \ | ||
Lacking permissions needed to create directory %s" | ||
(Path.to_string t.dir) | ||
|
||
let report_uncreated_file = function | ||
| Ok _ -> () | ||
| Error path -> | ||
Errors.kerrf ~f:print_to_console | ||
"@{<warning>Warning@}: file @{<kwd>%s@} was not created \ | ||
because it already exists\n" | ||
(Path.to_string path) | ||
|
||
let create_files t = | ||
t.files | ||
|> List.map ~f:File.create | ||
|> List.iter ~f:report_uncreated_file | ||
|
||
let create t = | ||
create_dir t; | ||
create_files t | ||
end | ||
|
||
let validate_project_name name = | ||
match Lib_name.Local.of_string name with | ||
| Ok _ -> () | ||
| _ -> Exn.fatalf "A project named '%s' cannot be created because it is an %s" | ||
name Lib_name.Local.invalid_message | ||
|
||
let make_project_dirs (c : Init_context.t) = | ||
(* dirs that are always included in a project *) | ||
let project_dirs = | ||
[ | ||
Project_dir.root c; (* The project dir should always be first *) | ||
Project_dir.lib c; | ||
] | ||
in | ||
let project_dirs = match c.kind with | ||
| Kind.Library -> project_dirs | ||
| Kind.Executable -> project_dirs @ [Project_dir.bin c] | ||
in | ||
List.iter ~f:Project_dir.create project_dirs | ||
|
||
let print_completion (c : Init_context.t) = | ||
Errors.kerrf ~f:print_to_console | ||
"@{<ok>Success@}: initialized %s project @{<kwd>%s@}\n" | ||
(Kind.to_string c.kind) c.pname | ||
|
||
let make_project pname kind path = | ||
validate_project_name pname; | ||
let context = Init_context.make pname kind path in | ||
make_project_dirs context; | ||
print_completion context |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
open! Stdune | ||
|
||
(** Supported kinds of projects for initialization *) | ||
module Kind : sig | ||
type t = | ||
| Library | ||
| Executable | ||
end | ||
|
||
(** [make_project pname kind path] will make a project of the given [kind] | ||
with the supplied [pname], at the optional [path] (defaulting to the | ||
current working directory if the [path] is [None]). *) | ||
val make_project : string -> Kind.t -> string option -> unit |