documents¶

In [ ]:
open file_system_operators
open sm'_operators
open rust.rust_operators
open rust
In [ ]:
///- --test static

open testing

args¶

In [ ]:
inl get_args () =
    {
        source_dir = "source-dir", 's'
        dist_dir = "dist-dir", 'd'
        cache_dir = "cache-dir", 'c'
        hangul_spec = "hangul-spec", 'H'
        filter = "filter", 'f'
        transcribe_only = "transcribe-only", 't'
    }

get_command¶

In [ ]:
let get_command () =
    ###"command"
    |> runtime.new_command
    |> runtime.command_init_arg (get_args () .source_dir) (
        runtime.arg_required true
    )
    |> runtime.command_init_arg (get_args () .dist_dir) (
        runtime.arg_required true
    )
    |> runtime.command_init_arg (get_args () .cache_dir) (
        runtime.arg_required true
    )
    |> runtime.command_init_arg (get_args () .hangul_spec) (
        id
    )
    |> runtime.command_init_arg (get_args () .filter) (
        id
    )
    |> runtime.command_init_arg (get_args () .transcribe_only) (
        runtime.arg_default_value "false"
        >> runtime.arg_action runtime.SetTrue
    )

crowbook¶

In [ ]:
let crowbook hangul { ext dist_dir dist_path output_path } =
    inl exit_code, result =
        inl args =
            inl default ext =
                $'$" rendering.num_depth 6"'
                ++# $'$" rendering.highlight.theme \\\\\\"Solarized (dark)\\\\\\""'
            match ext with
            | "html" =>
                $'$"--set"'
                ++# $'$" html.css.add \\\\\\"\'"'
                ++# $'$" body {{ color: \#e8e6e3; background-color: \#202324; }}"'
                ++# $'$" a {{ color: \#989693; }}"'
                ++# $'$" pre {{ background-color: \#1b1b1b; padding: 10px; }}"'
                ++# $'$" \'\\\\\\""'
                ++# default ext
            | "pdf" =>
                $'$"--set"'
                ++# $'$" tex.paper.size a4paper"'
                ++# $'$" tex.command tectonic"'
                ++# $'$" tex.template.add \\\"\\\\pagenumbering{{gobble}}\\\""'
                ++# (
                    if hangul |> not
                    then ""
                    else
                        $'$" tex.template.add \\\"\\\\usepackage{{polyglossia}}\\\""'
                        ++# $'$" tex.template.add \\\"\\\\setmainlanguage{{korean}}\\\""'
                        ++# $'$" tex.template.add \\\"\\\\setmainfont{{NanumGothicCoding}}\\\""'
                        ++# $'$" tex.font.size 13"'
                )
                ++# default ext
            | "epub" =>
                $'$"--set"'
                ++# $'$" epub.version 3"'
                ++# $'$" html.css.add \\\\\\"\' "'
                ++# $'$" body {{ color: \#e8e6e3; background-color: \#202324; }} "'
                ++# $'$" a {{ color: \#989693; }} "'
                ++# $'$" \'\\\\\\""'
                ++# default ext
            | _ => ""
        inl exit_code, result =
            runtime.execution_options fun x => { x with
                command =
                    $'$"crowbook --verbose --to {!ext}"'
                    ++# $'$" --single \\\"{!dist_path}\\\" --output \\\"{!output_path}\\\" {!args}"'
                working_directory = dist_dir |> Some |> optionm'.box
            }
            |> runtime.execute_with_options

        if exit_code = 0
        then exit_code, result
        else
            trace Warning
                fun () => "documents.crowbook / attempt error"
                fun () => { exit_code output_path result }
            runtime.execution_options fun x => { x with
                command =
                    $'$"crowbook --verbose --to {!ext}"'
                    ++# $'$" --single \\\"{!dist_path}\\\" --output \\\"{!output_path}\\\""'
                    ++# (if ext = "pdf" then $'$" --set tex.command tectonic"' else "")
                working_directory = dist_dir |> Some |> optionm'.box
            }
            |> runtime.execute_with_options


    if result |> sm'.contains "ERROR" |> not
    then (exit_code, result) |> Ok
    else
        trace Warning
            fun () => "documents.crowbook / result contains ERROR"
            fun () => { exit_code output_path result }
        (exit_code, result) |> Error

hangul¶

In [ ]:
let hangul workspace_root hangul_spec transcribe_only { ext dist_dir dist_path output_path } =
    inl lines =
        dist_path
        |> file_system.read_all_text
        |> sm'.split "\n"
        |> fun x => a x : _ int _
        |> am.map sm'.trim
    inl text =
        lines
        |> am.filter fun line => line <>. ""
        |> seq.of_array'
        |> sm'.concat "\n"
        |> fun x => $'$"{!x}\n\n"'
    inl hangul_spec =
        if (text |> sm'.contains " the ")
            && (text |> sm'.contains " and ")
        then "eng"
        else hangul_spec
    inl exit_code, result =
        runtime.execution_options fun x => { x with
            command =
                inl hangulize_path =
                    workspace_root </> $'$"../alphabet/deps/hangulize/cmd/hangulize/hangulize{!(platform.get_executable_suffix ())}"'
                $'$"{!hangulize_path} {!hangul_spec}"'
            stdin =
                fun stdin =>
                    inl stdin =
                        stdin
                        |> threading.arc_mutex_lock
                        |> resultm.unwrap'
                    text |> runtime.stdin_write_all stdin
                |> Some |> optionm'.box
        }
        |> runtime.execute_with_options
    inl result =
        inl result =
            result
            |> sm'.split "\n"
            |> fun x => a x : _ int _
        inl result_len = result |> am'.length
        (("", (0, 0), false), lines)
        ||> am.fold fun (acc, (i, n), in_code_block) line =>
            if line = ""
            then acc ++# "\n", (i + 1, n + 1), in_code_block
            else
                inl code_fence = line |> sm'.starts_with "```"
                inl acc =
                    inl i = i - n
                    if i >= result_len
                    then acc
                    elif code_fence || in_code_block
                    then
                        inl result = acc ++# line
                        if i = result_len - 1
                        then result
                        else result ++# "\n"
                    else
                        inl new_line = result |> am'.index i
                        inl new_line =
                            if new_line |> sm'.contains "://"
                            then line
                            else new_line
                        inl result = acc ++# new_line
                        inl result =
                            if transcribe_only
                            then result
                            else result ++# "\n" ++# line
                        if i = result_len - 1
                        then result
                        else result ++# "\n"
                acc, (i + 1, n), (if code_fence then in_code_block |> not else in_code_block)
        |> fun (acc, _, _) => acc
    result |> file_system.write_all_text output_path
    trace Info
        fun () => "documents.hangul"
        fun () => { exit_code result_len = ##result; output_path }
    (exit_code, result) |> Ok
    |> fun x => x : result (int * string) (int * string)

fix_paths¶

In [ ]:
let fix_paths { cache_dir dist_path ext } =
    inl file_name = dist_path |> file_system.get_file_name
    inl cache_path = cache_dir </> file_name
    inl dist_path_no_ext =
        dist_path
        |> sm'.slice 0 ((dist_path |> sm'.last_index_of ".") - 1)
    inl cache_path_no_ext =
        cache_path
        |> sm'.slice 0 ((cache_path |> sm'.last_index_of ".") - 1)
    inl is_md = ext |> sm'.ends_with ".md"
    inl output_path : string =
        if is_md |> not
        then $'$"{!dist_path}.{!ext}"'
        else $'$"{!dist_path_no_ext}.{!ext}"'
    inl output_cache_path : string =
        if is_md |> not
        then $'$"{!cache_path}.{!ext}"'
        else $'$"{!cache_path_no_ext}.{!ext}"'
    { output_path output_cache_path }

files_fn¶

In [ ]:
inl files_fn { dist_dir cache_dir } fn dist_path ext =
    inl { output_path output_cache_path } = fix_paths { cache_dir dist_path ext }
    inl equal =
        if (output_path |> file_system.file_exists |> not)
            || (output_cache_path |> file_system.file_exists |> not)
        then false
        else
            inl output_hash =
                output_path
                |> crypto.get_file_hash
                |> resultm.map_error' sm'.format'
                |> resultm.unbox'
                |> resultm.get
            inl output_cache_hash =
                output_cache_path
                |> crypto.get_file_hash
                |> resultm.map_error' sm'.format'
                |> resultm.unbox'
                |> resultm.get
            output_hash = output_cache_hash
    if equal
    then None
    else
        match fn { ext dist_dir dist_path output_path } with
        | Ok (exit_code, result) when exit_code <>. 0 =>
            trace Info
                fun () => "documents.files_fn / error"
                fun () => { exit_code result }
            new_pair output_path result |> Error |> resultm.box |> Some
        | Error (exit_code, result) =>
            new_pair output_path result |> Error |> resultm.box |> Some
        | _ =>
            if output_path |> file_system.file_exists
            then output_path |> file_system.file_copy output_cache_path
            else failwith $'$"documents.files_fn / {!output_path} should exist"'
            output_path |> Ok |> resultm.box |> Some

run¶

In [ ]:
let run { source_dir dist_dir cache_dir hangul_spec filter transcribe_only }
    : async.future_pin (
        resultm.result'
            (am'.vec (
                resultm.result'
                    (pair string (am'.vec (optionm'.option' (resultm.result' string (pair string string)))))
                    sm'.std_string
            ))
            sm'.std_string
    )
    =
    inl workspace_root = file_system.get_workspace_root ()
    inl source_dir = source_dir |> file_system.get_full_path
    inl dist_dir = dist_dir |> file_system.get_full_path
    inl cache_dir = cache_dir |> file_system.get_full_path
    trace Debug
        fun () => "documents.run"
        fun () => { source_dir dist_dir cache_dir hangul_spec filter transcribe_only }
    fun () =>
        inl files =
            run_target function
                | Rust => fun () =>
                    inl filter, has_filter = match filter with Some filter => filter, true | None => "", false
                    $'{ let mut out: Vec<Rc<str>> = Vec::new(); let mut stack = vec\![std::path::PathBuf::from(&*!dist_dir)]; while let Some(dir) = stack.pop() { if let Ok(entries) = std::fs::read_dir(&dir) { for entry in entries.flatten() { let path = entry.path(); if path.is_dir() { stack.push(path) } else { let s = path.display().to_string(); if s.ends_with(".md") && \!s.ends_with(".hangul.md") && (\!!has_filter || s.contains(&*!filter)) { out.push(Rc::from(s.as_str())) } } } } } out }' : am'.vec string
                | _ => fun () =>
                    dist_dir
                    |> file_system.new_walk_dir
                    |> file_system.walk_dir_filter fun entry => async.new_future_move_send fun () =>
                        entry
                        |> file_system.dir_entry_file_type
                        |> async.await_send
                        |> resultm.map_error' sm'.format'
                        |> resultm.unbox
                        |> function
                            | Ok file_type when file_type |> file_system.file_type_is_dir =>
                                file_system.Ignore
                            | _ =>
                                inl path =
                                    entry
                                    |> file_system.dir_entry_path
                                    |> file_system.path_buf_display
                                    |> sm'.format'
                                    |> sm'.from_std_string
                                if (path |> sm'.ends_with ".md" |> not)
                                    || (
                                        match filter with
                                        | Some filter => path |> sm'.contains filter |> not
                                        | None => false
                                    )
                                    || (path |> sm'.ends_with ".hangul.md")
                                then file_system.Ignore
                                else file_system.Continue
                    |> async.stream_filter_map_futures fun (entry : _ _ file_system.async_walkdir_error) =>
                        match entry |> resultm.map_error' sm'.format' |> resultm.unbox with
                        | Ok entry =>
                            entry
                            |> file_system.dir_entry_path
                            |> file_system.path_buf_display
                            |> sm'.format'
                            |> sm'.from_std_string
                            |> Some
                        | Error error =>
                            trace Critical
                                fun () => "documents.run / stream_filter_map"
                                fun () => { error }
                            None
                        |> optionm'.box
                    |> async.stream_collect_futures
                    |> async.await
        trace Debug
            fun () => "documents.run"
            fun () => { files_len = files |> am'.vec_len }
        files
        |> async.into_par_iter
        |> async.par_map fun file =>
            inl file = file |> file_system.get_full_path
            inl relative_path =
                file
                |> sm'.to_std_string
                |> file_system.new_path_buf
                |> file_system.path_buf_display
                |> sm'.format'
                |> sm'.from_std_string
                |> sm'.replace dist_dir (join "")
                |> sm'.replace "\\" "/"
                |> fun s => $'$".{!s}"'
            inl file = file |> file_system.normalize_path
            inl real_path = source_dir </> relative_path |> file_system.standardize_path
            inl origin_hash_exit_code, origin_hash =
                runtime.execution_options fun x => { x with
                    command =
                        $'$"git ls-tree --format=\'%%(objectname)\' origin/gh-pages \\"{!real_path}\\""'
                    working_directory = source_dir |> Some |> optionm'.box
                }
                |> runtime.execute_with_options
            inl dist_path = dist_dir </> relative_path |> file_system.standardize_path
            inl local_git_hash_exit_code, local_git_hash =
                runtime.execution_options fun x => { x with
                    command = $'$"git hash-object \\"{!dist_path}\\""'
                    working_directory = dist_dir |> Some |> optionm'.box
                }
                |> runtime.execute_with_options
            inl cache_path = cache_dir </> relative_path |> file_system.standardize_path
            inl files =
                inl files_fn = files_fn { dist_dir cache_dir }
                inl files = [
                    "hangul.md", dist_path, hangul workspace_root hangul_spec transcribe_only |> files_fn
                ]
                inl { output_path } = fix_paths { dist_path cache_dir ext = "hangul.md" }
                inl files' = [
                    "html", dist_path, crowbook false |> files_fn
                    "pdf", dist_path, crowbook false |> files_fn
                    "epub", dist_path, crowbook false |> files_fn
                    "html", output_path, crowbook true |> files_fn
                    "pdf", output_path, crowbook true |> files_fn
                    "epub", output_path, crowbook true |> files_fn
                ]
                [ files; files' ]
            inl files' =
                if origin_hash |> sm'.contains local_git_hash
                then []
                else
                    inl hash1 =
                        dist_path
                        |> crypto.get_file_hash
                        |> resultm.map_error' sm'.format'
                        |> resultm.unbox'
                        |> resultm.get
                    inl hash2 =
                        if cache_path |> file_system.file_exists |> not
                        then None
                        else
                            cache_path
                            |> crypto.get_file_hash
                            |> resultm.map_error' sm'.format'
                            |> resultm.unbox'
                            |> resultm.ok
                    match hash2 with
                    | Some hash2 when hash1 = hash2 => []
                    | _ =>
                        trace Info
                            fun () =>
                                "documents.run / par_map"
                                ++# " / origin_hash |> sm\'.contains local_git_hash |> not"
                                ++# " / Some hash2 when hash1 = hash2"
                            fun () => {
                                file
                                real_path
                                relative_path
                                origin_hash_exit_code
                                origin_hash
                                local_git_hash_exit_code
                                local_git_hash
                                hash1
                                hash2
                                dist_path
                                cache_path
                            }
                        dist_path |> file_system.file_copy cache_path
                        files
            inl files' =
                if files' <> []
                then files'
                else
                    files
                    |> listm.map fun files =>
                        files
                        |> listm'.filter fun ext, path, fn =>
                            inl { output_path output_cache_path } =
                                fix_paths { cache_dir dist_path = path; ext }
                            if output_path |> file_system.file_exists
                            then true
                            elif output_cache_path |> file_system.file_exists |> not
                            then true
                            else
                                trace Info
                                    fun () => "documents.run / par_map / files\' = [] / listm.iter"
                                    fun () => { output_path output_cache_path }
                                output_cache_path |> file_system.file_copy output_path
                                false
            files'
            |> listm'.box
            |> listm'.to_array'
            |> am'.to_vec
            |> am'.vec_collect fun files =>
                files
                |> listm'.box
                |> listm'.to_array'
                |> am'.to_vec
                |> async.into_par_iter
                |> async.par_map fun ext, path, fn =>
                    fn path ext |> optionm'.box
                |> async.par_collect
            |> new_pair file
            |> Ok
            |> resultm.box
        |> async.par_collect
        |> Ok
        |> resultm.box
    |> async.new_future_move
In [1]:
///- --test
///> rust -d async-walkdir encoding_rs encoding_rs_io futures futures-lite rayon regex sha2

inl workspace_root = file_system.get_workspace_root ()
inl source_dir = workspace_root </> "../alphabet/target/documents"
inl dist_dir = source_dir </> "dist"
inl cache_dir = source_dir </> "cache"
inl file_name_no_ext = "test"
inl file_name = join $'$"{!file_name_no_ext}.md"'

source_dir |> file_system.directory_delete true
dist_dir |> file_system.directory_delete true
cache_dir |> file_system.directory_delete true

source_dir |> file_system.create_dir |> ignore
dist_dir |> file_system.create_dir |> ignore
cache_dir |> file_system.create_dir |> ignore

inl text = """
    # a

    ## b

    ---

    abc
    abc

    abc

    http://abc.com
    abc

    """
text |> file_system.write_all_text (source_dir </> file_name)
text |> file_system.write_all_text (dist_dir </> file_name)

inl html_path = dist_dir </> $'$"{!file_name}.html"' |> file_system.absolute_path
inl pdf_path = dist_dir </> $'$"{!file_name}.pdf"' |> file_system.absolute_path
inl epub_path = dist_dir </> $'$"{!file_name}.epub"' |> file_system.absolute_path
inl hangul_path = dist_dir </> $'$"{!file_name_no_ext}.hangul.md"' |> file_system.absolute_path
inl hangul_html_path = dist_dir </> $'$"{!file_name_no_ext}.hangul.md.html"' |> file_system.absolute_path
inl hangul_pdf_path = dist_dir </> $'$"{!file_name_no_ext}.hangul.md.pdf"' |> file_system.absolute_path
inl hangul_epub_path = dist_dir </> $'$"{!file_name_no_ext}.hangul.md.epub"' |> file_system.absolute_path

run {
    source_dir
    dist_dir
    cache_dir
    hangul_spec = "por-br"
    filter = None
    transcribe_only = false
}
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.format_debug'
|> sm'.from_std_string
|> _assert_eq (
    ;[
        Ok (
            (dist_dir </> file_name |> file_system.absolute_path),
            ;[
                hangul_path
                html_path
                pdf_path
                epub_path
                hangul_html_path
                hangul_pdf_path
                hangul_epub_path
            ]
            |> am'.to_vec |> am'.vec_map (Ok >> resultm.box >> Some >> optionm'.box)
            |> fun x => x : _ (_ (_ _ sm'.std_string))
        )
    ]
    |> am'.to_vec
    |> am'.vec_map resultm.box
    |> fun x => x : _ (_ _ sm'.std_string)
    |> sm'.format_debug'
    |> sm'.from_std_string
)

dist_dir |> file_system.directory_delete true
dist_dir |> file_system.create_dir |> ignore

text |> file_system.write_all_text (dist_dir </> file_name)

run {
    source_dir = source_dir
    dist_dir = dist_dir
    cache_dir = cache_dir
    hangul_spec = "por-br"
    filter = None
    transcribe_only = false
}
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.format_debug'
|> sm'.from_std_string
|> _assert_eq (
    ;[
        Ok (
            (dist_dir </> file_name |> file_system.absolute_path),
            ;[]
            |> am'.to_vec |> am'.vec_map ((optionm.map resultm.box) >> optionm'.box)
        )
    ]
    |> am'.to_vec
    |> am'.vec_map resultm.box
    |> fun x =>
        x : am'.vec (
            resultm.result'
                (string * am'.vec (optionm'.option' (resultm.result' string string)))
                sm'.std_string
        )
    |> sm'.format_debug'
    |> sm'.from_std_string
)

run {
    source_dir = source_dir
    dist_dir = dist_dir
    cache_dir = cache_dir
    hangul_spec = "por-br"
    filter = None
    transcribe_only = false
}
|> async.block_on_futures
|> resultm.unwrap'
|> sm'.format_debug'
|> sm'.from_std_string
|> _assert_eq (
    ;[
        Ok (
            (dist_dir </> file_name |> file_system.absolute_path),
            ;[ None; None; None; None; None; None; None ]
            |> am'.to_vec |> am'.vec_map ((optionm.map resultm.box) >> optionm'.box)
        )
    ]
    |> am'.to_vec
    |> am'.vec_map resultm.box
    |> fun x =>
        x : am'.vec (
            resultm.result'
                (string * am'.vec (optionm'.option' (resultm.result' string string)))
                sm'.std_string
        )
    |> sm'.format_debug'
    |> sm'.from_std_string
)

hangul_path
|> file_system.read_all_text
|> _assert_eq (
    "# 아"
    ++\# "# a"
    ++\# ""
    ++\# "## 브"
    ++\# "## b"
    ++\# ""
    ++\# "---"
    ++\# "---"
    ++\# ""
    ++\# "아브크"
    ++\# "abc"
    ++\# "아브크"
    ++\# "abc"
    ++\# ""
    ++\# "아브크"
    ++\# "abc"
    ++\# ""
    ++\# "http://abc.com"
    ++\# "http://abc.com"
    ++\# "아브크"
    ++\# "abc"
    ++\# ""
)

html_path
|> file_system.read_all_text
|> sm'.contains "<p class = \"rule\">***</p>\n<p id = \"para-1\">abc abc</p>"
|> _assert_eq true

pdf_path
|> file_system.read_all_bytes
|> sm'.slice_contains "%PDF-1.5"
|> _assert_eq true

epub_path
|> file_system.read_all_bytes
|> sm'.slice_contains "application/epub+zip"
|> _assert_eq true

hangul_html_path
|> file_system.read_all_text
|> sm'.contains "<p class = \"rule\">***</p>\n<p id = \"para-1\">아브크 abc 아브크 abc</p>"
|> _assert_eq true

hangul_pdf_path
|> file_system.read_all_bytes
|> sm'.slice_contains "%PDF-1.5"
|> _assert_eq true

hangul_epub_path
|> file_system.read_all_bytes
|> sm'.slice_contains "application/epub+zip"
|> _assert_eq true
16:30:19 1v file_system.create_dir / { dir = /home/runner/work/alphabet/spiral/../alphabet/target/documents }
16:30:19 2v file_system.create_dir / { dir = /home/runner/work/alphabet/spiral/../alphabet/target/documents/dist }
16:30:19 3v file_system.create_dir / { dir = /home/runner/work/alphabet/spiral/../alphabet/target/documents/cache }
16:30:19 4d documents.run / { source_dir = /home/runner/work/alphabet/alphabet/target/documents; dist_dir = /home/runner/work/alphabet/alphabet/target/documents/dist; cache_dir = /home/runner/work/alphabet/alphabet/target/documents/cache; hangul_spec = por-br; filter = None; transcribe_only = false }
16:30:19 5d documents.run / { files_len = 1 }
16:30:19 6d runtime.execute_with_options / { file_name = git; arguments = ["ls-tree", "--format='%(objectname)'", "origin/gh-pages", "/home/runner/work/alphabet/alphabet/target/documents/test.md"] }
16:30:19 7v ! fatal: Not a valid object name origin/gh-pages
16:30:19 8v runtime.execute_with_options / result / { file_name = git; exit_code = 128; std_trace_len = 56 }
16:30:19 9d runtime.execute_with_options / { file_name = git; arguments = ["hash-object", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md"] }
16:30:19 10v > 6358eb3bcf1cbb2b0cdddbd569507e44386e02c3
16:30:19 11v runtime.execute_with_options / result / { file_name = git; exit_code = 0; std_trace_len = 40 }
16:30:19 12i documents.run / par_map / origin_hash |> sm'.contains local_git_hash |> not / Some hash2 when hash1 = hash2 / { file = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md; real_path = /home/runner/work/alphabet/alphabet/target/documents/test.md; relative_path = ./test.md; origin_hash_exit_code = 128; origin_hash = fatal: Not a valid object name origin/gh-pages; local_git_hash_exit_code = 0; local_git_hash = 6358eb3bcf1cbb2b0cdddbd569507e44386e02c3; hash1 = e75e7fe031d4e828aadbec1ce37f56969e7da7baa427b6866c0ed8ac1a86b107; hash2 = None; dist_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md; cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md }
16:30:19 13d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md; result = 49 }
16:30:19 14d runtime.execute_with_options / { file_name = /home/runner/work/alphabet/spiral/../alphabet/deps/hangulize/cmd/hangulize/hangulize; arguments = ["por-br"] }
16:30:19 15v > # 아
16:30:19 16v > ## 브
16:30:19 17v > ---
16:30:19 18v > 아브크
16:30:19 19v > 아브크
16:30:19 20v > 아브크
16:30:19 21v > 트프://아브크.콩
16:30:19 22v > 아브크
16:30:19 23v runtime.execute_with_options / result / { file_name = /home/runner/work/alphabet/spiral/../alphabet/deps/hangulize/cmd/hangulize/hangulize; exit_code = 0; std_trace_len = 79 }
16:30:19 24i documents.hangul / { exit_code = 0; result_len = 121; output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md }
16:30:19 25d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md; result = 121 }
16:30:19 26d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "html", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.html", "--set", "html.css.add", "' body { color: #e8e6e3; background-color: #202324; } a { color: #989693; } pre { background-color: #1b1b1b; padding: 10px; } '", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:30:19 27v ! CROWBOOK 0.17.1
16:30:19 28v ! 16:30:19 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:30:19 29v !
16:30:19 30v ! 16:30:19 [DEBUG] (1) crowbook::book: Attempting to generate html...
16:30:19 31v ! 16:30:19 [DEBUG] (1) epub_builder::toc: rendered elem: "<li>\n  <a href=\"#link-1\">1. a</a>\n  <ul>\n    <li><a href=\"#link-2\">1.1. b</a></li>\n  </ul>\n</li>"
16:30:19 32v ! 16:30:19 [INFO] crowbook::book: Succesfully generated HTML (standalone page): test.md.html
16:30:19 33v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 456 }
16:30:19 34d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.html; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.html; result = 11691 }
16:30:19 35d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "pdf", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.pdf", "--set", "tex.paper.size", "a4paper", "tex.command", "tectonic", "tex.template.add", "\\pagenumbering{gobble}", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:30:19 36v ! CROWBOOK 0.17.1
16:30:19 37v ! 16:30:19 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:30:19 38v !
16:30:19 39v ! 16:30:19 [DEBUG] (1) crowbook::book: Attempting to generate pdf...
16:30:19 40v ! 16:30:19 [DEBUG] (1) crowbook::latex: Attempting to run LaTeX on generated file
16:31:28 41v ! 16:31:28 [INFO] crowbook::book: Succesfully generated PDF: test.md.pdf
16:31:28 42v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 352 }
16:31:28 43d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.pdf; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.pdf; result = 6594 }
16:31:28 44d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "epub", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.epub", "--set", "epub.version", "3", "html.css.add", "'  body { color: #e8e6e3; background-color: #202324; }  a { color: #989693; }  '", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:31:28 45v ! CROWBOOK 0.17.1
16:31:28 46v ! 16:31:28 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:31:28 47v !
16:31:28 48v ! 16:31:28 [DEBUG] (1) crowbook::book: Attempting to generate epub...
16:31:28 49v ! 16:31:28 [DEBUG] (1) epub_builder::epub: Add resource: "stylesheet.css"
16:31:28 50v ! 16:31:28 [DEBUG] (1) epub_builder::epub: render_opf...
16:31:28 51v ! 16:31:28 [DEBUG] (1) epub_builder::epub: id="id_title_page.xhtml", mime="application/xhtml+xml"
16:31:28 52v ! 16:31:28 [DEBUG] (1) epub_builder::epub: content = Content { file: "title_page.xhtml", mime: "application/xhtml+xml", itemref: true, cover: false, reftype: Some(TitlePage), title: "Title" }
16:31:28 53v ! 16:31:28 [DEBUG] (1) epub_builder::epub: id="id_chapter_000.xhtml", mime="application/xhtml+xml"
16:31:28 54v ! 16:31:28 [DEBUG] (1) epub_builder::epub: content = Content { file: "chapter_000.xhtml", mime: "application/xhtml+xml", itemref: true, cover: false, reftype: Some(Text), title: "1. a" }
16:31:28 55v ! 16:31:28 [DEBUG] (1) epub_builder::epub: id="id_stylesheet.css", mime="text/css"
16:31:28 56v ! 16:31:28 [DEBUG] (1) epub_builder::toc: rendered elem: "<li><a href=\"title_page.xhtml\">Title</a></li>"
16:31:28 57v ! 16:31:28 [DEBUG] (1) epub_builder::toc: rendered elem: "<li>\n  <a href=\"chapter_000.xhtml\">1. a</a>\n  <ol>\n    <li><a href=\"chapter_000.xhtml#link-2\">1.1. b</a></li>\n  </ol>\n</li>"
16:31:28 58v ! 16:31:28 [INFO] crowbook::book: Succesfully generated EPUB: test.md.epub
16:31:28 59v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 1426 }
16:31:28 60d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.epub; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.epub; result = 5043 }
16:31:28 61d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "html", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.html", "--set", "html.css.add", "' body { color: #e8e6e3; background-color: #202324; } a { color: #989693; } pre { background-color: #1b1b1b; padding: 10px; } '", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:31:28 62v ! CROWBOOK 0.17.1
16:31:28 63v ! 16:31:28 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:31:28 64v !
16:31:28 65v ! 16:31:28 [DEBUG] (1) crowbook::book: Attempting to generate html...
16:31:28 66v ! 16:31:28 [DEBUG] (1) epub_builder::toc: rendered elem: "<li><a href=\"#link-1\">1. 아</a></li>"
16:31:28 67v ! 16:31:28 [DEBUG] (1) epub_builder::toc: rendered elem: "<li>\n  <a href=\"#link-2\">2. a</a>\n  <ul>\n    <li><a href=\"#link-3\">2.1. 브</a></li>\n    <li><a href=\"#link-4\">2.2. b</a></li>\n  </ul>\n</li>"
16:31:28 68v ! 16:31:28 [INFO] crowbook::book: Succesfully generated HTML (standalone page): test.hangul.md.html
16:31:28 69v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 617 }
16:31:28 70d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.html; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.html; result = 16077 }
16:31:28 71d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "pdf", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.pdf", "--set", "tex.paper.size", "a4paper", "tex.command", "tectonic", "tex.template.add", "\\pagenumbering{gobble}", "tex.template.add", "\\usepackage{polyglossia}", "tex.template.add", "\\setmainlanguage{korean}", "tex.template.add", "\\setmainfont{NanumGothicCoding}", "tex.font.size", "13", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:31:28 72v ! CROWBOOK 0.17.1
16:31:28 73v ! 16:31:28 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:31:28 74v !
16:31:28 75v ! 16:31:28 [DEBUG] (1) crowbook::book: Attempting to generate pdf...
16:31:28 76v ! 16:31:28 [DEBUG] (1) crowbook::latex: Attempting to run LaTeX on generated file
16:31:31 77v ! 16:31:31 [INFO] crowbook::book: Succesfully generated PDF: test.hangul.md.pdf
16:31:31 78v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 359 }
16:31:31 79d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.pdf; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.pdf; result = 12243 }
16:31:31 80d runtime.execute_with_options / { file_name = crowbook; arguments = ["--verbose", "--to", "epub", "--single", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md", "--output", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.epub", "--set", "epub.version", "3", "html.css.add", "'  body { color: #e8e6e3; background-color: #202324; }  a { color: #989693; }  '", "rendering.num_depth", "6", "rendering.highlight.theme", "Solarized (dark)"] }
16:31:31 81v ! CROWBOOK 0.17.1
16:31:31 82v ! 16:31:31 [DEBUG] (1) crowbook::book: Ignoring YAML block:
16:31:31 83v !
16:31:31 84v ! 16:31:31 [DEBUG] (1) crowbook::book: Attempting to generate epub...
16:31:31 85v ! 16:31:31 [WARN] crowbook::epub: EPUB (test.hangul.md): detected two chapters inside the same markdown file.
16:31:31 86v ! 16:31:31 [WARN] crowbook::epub: EPUB ({source}): conflict between: 1. 아 and 2. a
16:31:31 87v ! 16:31:31 [DEBUG] (1) epub_builder::epub: Add resource: "stylesheet.css"
16:31:31 88v ! 16:31:31 [DEBUG] (1) epub_builder::epub: render_opf...
16:31:31 89v ! 16:31:31 [DEBUG] (1) epub_builder::epub: id="id_title_page.xhtml", mime="application/xhtml+xml"
16:31:31 90v ! 16:31:31 [DEBUG] (1) epub_builder::epub: content = Content { file: "title_page.xhtml", mime: "application/xhtml+xml", itemref: true, cover: false, reftype: Some(TitlePage), title: "Title" }
16:31:31 91v ! 16:31:31 [DEBUG] (1) epub_builder::epub: id="id_chapter_000.xhtml", mime="application/xhtml+xml"
16:31:31 92v ! 16:31:31 [DEBUG] (1) epub_builder::epub: content = Content { file: "chapter_000.xhtml", mime: "application/xhtml+xml", itemref: true, cover: false, reftype: Some(Text), title: "1. 아" }
16:31:31 93v ! 16:31:31 [DEBUG] (1) epub_builder::epub: id="id_stylesheet.css", mime="text/css"
16:31:31 94v ! 16:31:31 [DEBUG] (1) epub_builder::toc: rendered elem: "<li><a href=\"title_page.xhtml\">Title</a></li>"
16:31:31 95v ! 16:31:31 [DEBUG] (1) epub_builder::toc: rendered elem: "<li><a href=\"chapter_000.xhtml\">1. 아</a></li>"
16:31:31 96v ! 16:31:31 [INFO] crowbook::book: Succesfully generated EPUB: test.hangul.md.epub
16:31:31 97v runtime.execute_with_options / result / { file_name = crowbook; exit_code = 0; std_trace_len = 1563 }
16:31:31 98d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.epub; new_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.epub; result = 5048 }
__assert_eq { expected = [Ok(("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", [Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.html")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.pdf")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md.epub")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.html")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.pdf")), Some(Ok("/home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.epub"))]))] }
16:31:31 99v file_system.create_dir / { dir = /home/runner/work/alphabet/spiral/../alphabet/target/documents/dist }
16:31:31 100d documents.run / { source_dir = /home/runner/work/alphabet/alphabet/target/documents; dist_dir = /home/runner/work/alphabet/alphabet/target/documents/dist; cache_dir = /home/runner/work/alphabet/alphabet/target/documents/cache; hangul_spec = por-br; filter = None; transcribe_only = false }
16:31:31 101d documents.run / { files_len = 1 }
16:31:31 102d runtime.execute_with_options / { file_name = git; arguments = ["ls-tree", "--format='%(objectname)'", "origin/gh-pages", "/home/runner/work/alphabet/alphabet/target/documents/test.md"] }
16:31:31 103v ! fatal: Not a valid object name origin/gh-pages
16:31:31 104v runtime.execute_with_options / result / { file_name = git; exit_code = 128; std_trace_len = 56 }
16:31:31 105d runtime.execute_with_options / { file_name = git; arguments = ["hash-object", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md"] }
16:31:31 106v > 6358eb3bcf1cbb2b0cdddbd569507e44386e02c3
16:31:31 107v runtime.execute_with_options / result / { file_name = git; exit_code = 0; std_trace_len = 40 }
16:31:31 108i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.epub; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.epub }
16:31:31 109d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.epub; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.epub; result = 5048 }
16:31:31 110i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.pdf; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.pdf }
16:31:31 111d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.pdf; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.pdf; result = 12243 }
16:31:31 112i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.html; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.html }
16:31:31 113d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md.html; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md.html; result = 16077 }
16:31:31 114i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.epub; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.epub }
16:31:31 115d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.epub; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.epub; result = 5043 }
16:31:31 116i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.pdf; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.pdf }
16:31:31 117d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.pdf; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.pdf; result = 6594 }
16:31:31 118i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.html; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.html }
16:31:31 119d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.md.html; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.md.html; result = 11691 }
16:31:31 120i documents.run / par_map / files' = [] / listm.iter / { output_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md; output_cache_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md }
16:31:31 121d file_system.file_copy / { old_path = /home/runner/work/alphabet/alphabet/target/documents/cache/test.hangul.md; new_path = /home/runner/work/alphabet/alphabet/target/documents/dist/test.hangul.md; result = 121 }
__assert_eq { expected = [Ok(("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", []))] }
16:31:31 122d documents.run / { source_dir = /home/runner/work/alphabet/alphabet/target/documents; dist_dir = /home/runner/work/alphabet/alphabet/target/documents/dist; cache_dir = /home/runner/work/alphabet/alphabet/target/documents/cache; hangul_spec = por-br; filter = None; transcribe_only = false }
16:31:31 123d documents.run / { files_len = 1 }
16:31:31 124d runtime.execute_with_options / { file_name = git; arguments = ["ls-tree", "--format='%(objectname)'", "origin/gh-pages", "/home/runner/work/alphabet/alphabet/target/documents/test.md"] }
16:31:31 125v ! fatal: Not a valid object name origin/gh-pages
16:31:31 126v runtime.execute_with_options / result / { file_name = git; exit_code = 128; std_trace_len = 56 }
16:31:31 127d runtime.execute_with_options / { file_name = git; arguments = ["hash-object", "/home/runner/work/alphabet/alphabet/target/documents/dist/test.md"] }
16:31:31 128v > 6358eb3bcf1cbb2b0cdddbd569507e44386e02c3
16:31:31 129v runtime.execute_with_options / result / { file_name = git; exit_code = 0; std_trace_len = 40 }
__assert_eq { expected = [Ok(("/home/runner/work/alphabet/alphabet/target/documents/dist/test.md", [None, None, None, None, None, None, None]))] }
__assert_eq { expected = # 아
# a

## 브
## b

---
---

아브크
abc
아브크
abc

아브크
abc

http://abc.com
http://abc.com
아브크
abc
 }
__assert_eq { expected = true }
__assert_eq { expected = true }
__assert_eq { expected = true }
__assert_eq { expected = true }
__assert_eq { expected = true }
__assert_eq { expected = true }

tests¶

In [2]:
inl tests () =
    testing.run_tests {
        verify_app = get_command >> runtime.command_debug_assert
    }

main¶

In [ ]:
///> _

inl main (args : array_base string) =
    Info |> Some |> init_trace_state
    trace Info
        fun () => "documents.main"
        fun () => { args }
    inl command = get_command ()
    inl arg_matches = command |> runtime.command_get_matches
    inl source_dir =
        arg_matches
        |> runtime.matches_get_one (get_args () .source_dir |> fst)
        |> optionm'.unbox
        |> optionm.value
        |> sm'.from_std_string
    inl dist_dir =
        arg_matches
        |> runtime.matches_get_one (get_args () .dist_dir |> fst)
        |> optionm'.unbox
        |> optionm.value
        |> sm'.from_std_string
    inl cache_dir =
        arg_matches
        |> runtime.matches_get_one (get_args () .cache_dir |> fst)
        |> optionm'.unbox
        |> optionm.value
        |> sm'.from_std_string
    inl hangul_spec =
        arg_matches
        |> runtime.matches_get_one (get_args () .hangul_spec |> fst)
        |> optionm'.unbox
        |> optionm.map sm'.from_std_string
        |> optionm'.default_value "por-br"
    inl filter =
        arg_matches
        |> runtime.matches_get_one (get_args () .filter |> fst)
        |> optionm'.unbox
        |> optionm.map sm'.from_std_string
    inl transcribe_only =
        arg_matches
        |> runtime.matches_get_flag (get_args () .transcribe_only |> fst)
    inl result =
        run { source_dir dist_dir cache_dir hangul_spec filter transcribe_only }
        |> async.block_on_futures
        |> resultm.unbox
    match result with
    | Ok result =>
        trace Info
            fun () => "documents.main"
            fun () => { result_len = result |> am'.vec_len }
        0i32
    | Error error =>
        trace Critical
            fun () => "documents.main"
            fun () => { error }
        1i32
inl main () =
    backend_switch {
        Fsharp = fun () =>
            $'let tests () = !tests ()' : ()
            $'let main args = !main args' : ()
        Rust = fun () =>
            inl args =
                $'Rc::new(RefCell::new(std::env::args().skip(1).map(|x| Rc::<str>::from(x)).collect::<Vec<Rc<str>>>()))'
                : array_base string
            inl exit_code = main args
            $'if !exit_code \!= 0 { std::process::exit(!exit_code) }' : ()
    } : ()