Skip to content

Improve functions to run commands #389

Description

@Anton-4

The currently provided functions in Cmd don't result in the cleanest code. See the improvement in this diff where I added my own helper functions:

 main! : List Arg => Result {} _
 main! = |_args|
 
-    # get cwd to check if we are in the www dir
-    pwd_cmd_output =
-        Cmd.new("pwd")
-        |> Cmd.output!()
-
-    when pwd_cmd_output.status is
-        Ok(0) ->
-            pwd_bytes = pwd_cmd_output.stdout
-            
-            if !(List.ends_with(pwd_bytes, [119, 119, 119])) then
-                pwd_str = Str.from_utf8(pwd_bytes)?
-                Stderr.line!("You must run this script inside the 'www' directory, I am currently in: ${pwd_str}")?
-            else
-                {}
-        _ ->
-            Err(CommandPWDFailed(Inspect.to_str(pwd_cmd_output)))?
+    pwd_stdout_str = run_cmd_w_output!("pwd", [])?
+    if !(Str.ends_with(pwd_stdout_str, "/www")) then
+        Stderr.line!("You must run this script inside the 'www' directory, I am currently in: ${pwd_stdout_str}")?
+    else
+        {}
 
     # Clean up dirs from previous runs
     _ = Dir.delete_all!("build")
     _ = Dir.delete_all!("content/examples")
     _ = Dir.delete_all!("examples-main")
 
-    Cmd.exec!("cp", ["-r", "public", "build"]) ? |err| CopyPublicToBuildFailed(err)
-
+    run_cmd!("cp", ["-r", "content", "build"])?
 
     # Download latest examples
-    Cmd.exec!("curl", ["-fL", "-o", "examples-main.zip", "https://github.com/roc-lang/examples/archive/refs/heads/main.zip"]) ? |err| CurlDowloadExamplesRepoFailed(err)
-    
-    Cmd.exec!("unzip", ["-o", "-q", "examples-main.zip"]) ? |err| UnzipExamplesRepoFailed(err)
+    run_cmd!("curl", ["-fL", "-o", "examples-main.zip", "https://github.com/roc-lang/examples/archive/refs/heads/main.zip"])?
 
-    Cmd.exec!("cp", ["-R", "examples-main/examples/", "content/examples/"]) ? |err| CopyExamplesToContentFailed(err)
+    run_cmd!("unzip", ["-o", "-q", "examples-main.zip"])?
+
+    run_cmd!("cp", ["-R", "examples-main/examples/", "content/examples/"])?
 
     # replace links in content/examples/index.md to work on the WIP site
     # TODO do this in Roc
-    Cmd.exec!("perl", ["-pi", "-e", "s|\\]\\(/|\\]\\(/examples/|g", "content/examples/index.md"]) ? |err| PerlReplaceFailed(err)
+    run_cmd!("perl", ["-pi", "-e", "s|\\]\\(/|\\]\\(/examples/|g", "content/examples/index.md"])?
 
     Dir.delete_all!("examples-main") ? |err| DeleteExamplesMainDirFailed(err)
     File.delete!("examples-main.zip") ? |err| DeleteExamplesMainZipFailed(err)
@@ -55,11 +43,11 @@ main! = |_args|
     design_assets_tarfile = "roc-lang-design-assets-4d94964.tar.gz"
     design_assets_dir = "roc-lang-design-assets-4d94964"
 
-    Cmd.exec!("curl", ["-fLJO", "https://github.com/roc-lang/design-assets/tarball/${design_assets_commit}"]) ? |err| CurlDownloadDesignAssetsFailed(err)
+    run_cmd!("curl", ["-fLJO", "https://github.com/roc-lang/design-assets/tarball/${design_assets_commit}"])?
 
-    Cmd.exec!("tar", ["-xzf", design_assets_tarfile]) ? |err| TarExtractDesignAssetsFailed(err)
+    run_cmd!("tar", ["-xzf", design_assets_tarfile])?
 
-    Cmd.exec!("mv", ["${design_assets_dir}/fonts", "build/fonts"]) ? |err| MoveFontsToBuildFailed(err)
+    run_cmd!("mv", ["${design_assets_dir}/fonts", "build/fonts"])?
 
     # clean up
     Dir.delete_all!(design_assets_dir) ? |err| DeleteDesignAssetsDirFailed(err)
@@ -69,26 +57,30 @@ main! = |_args|
     repl_tarfile = "roc_repl_wasm.tar.gz"
 
     # Download the latest stable Web REPL as a zip file.
-    Cmd.exec!("curl", ["-fLJO", "https://github.com/roc-lang/roc/releases/download/alpha3-rolling/${repl_tarfile}"]) ? |err| CurlDownloadReplFailed(err)
-    
+    run_cmd!("curl", ["-fLJO", "https://github.com/roc-lang/roc/releases/download/alpha3-rolling/${repl_tarfile}"])?
+
     Dir.create!("build/repl") ? |err| CreateReplDirFailed(err)
 
-    Cmd.exec!("tar", ["-xzf", repl_tarfile, "-C", "build/repl"]) ? |err| TarExtractReplFailed(err)
+    run_cmd!("tar", ["-xzf", repl_tarfile, "-C", "build/repl"])?
 
     File.delete!(repl_tarfile) ? |err| DeleteReplTarFailed(err)
 
     # TODO generate docs for alpha3 instead of main branch
-    Cmd.exec!("roc", ["docs", "--output", "build/builtins", "--root-dir", "builtins"]) ? |err| RocGenDocsBuiltinsFailed(err)
+    run_cmd!("roc", ["docs", "--output", "build/builtins", "--root-dir", "builtins"])?
 
+    find_index_stdout = run_cmd_w_output!("find", ["www/build/builtins", "-type", "f", "-name", "index.html"])?
+    clean_paths = Str.split_on(find_index_stdout, "\n")
 
-    # Manually add this tip to all the builtin docs.
-    Cmd.exec!("find", ["www/build/builtins", "-type", "f", "-name", "index.html", "-exec", "sed", "-i", "'s!</nav>!<div class=\"builtins-tip\"><b>Tip:</b> <a href=\"/different-names\">Some names</a> differ from other languages.</div></nav>!'", "{}"]) ? |err| SedAddTipToBuiltinsDocsFailed(err)
+    List.for_each_try!(
+        clean_paths,
+        |path|
+            File.write_utf8!(path, Str.replace_each(File.read_utf8!(path)?, "</nav>", """<div class="builtins-tip"><b>Tip:</b> <a href="/different-names">Some names</a> differ from other languages.</div></nav>"""))
+    ) ? |err| WriteBuiltinsDocsReplaceFailed(err)
 
 
     # Generating site markdown content
-    Cmd.exec!("roc", ["build", "--linker", "legacy", "www/main.roc"]) ? |err| RocBuildStaticSiteMainFailed(err)
-    
-    Cmd.exec!("roc", ["www/main.roc", "www/content/", "www/build/"]) ? |err| RocRunStaticSiteMainFailed(err)
+    run_cmd!("roc", ["build", "--linker", "legacy", "www/main.roc"])?
+    run_cmd!("roc", ["www/main.roc", "www/content/", "www/build/"])?
 
 
     # Add github link to examples
@@ -102,29 +94,52 @@ main! = |_args|
         </svg>
         """
 
-    find_readme_html_output =
-        Cmd.new("find")
-        |> Cmd.args([examples_dir, "-type", "f", "-name", "README.html", "-exec", "realpath", "{}", ";"])
-        |> Cmd.output!()
+    find_readme_html_output = run_cmd_w_output!("find", [examples_dir, "-type", "f", "-name", "README.html", "-exec", "realpath", "{}", ";"])?
 
-    when find_readme_html_output.status is
-        Ok(0) ->
-            find_stdout = Str.from_utf8(find_readme_html_output.stdout)?
-            clean_readme_paths = Str.split_on(find_stdout, "\n")
-            # TODO check output as expected
+    clean_readme_paths = Str.split_on(find_readme_html_output, "\n")
+    # TODO check output as expected
 
-            List.for_each_try!(
-                clean_readme_paths,
-                |readme_path|
-                    readme_html_str = File.read_utf8!(readme_path)?
+    List.for_each_try!(
+        clean_readme_paths,
+        |readme_path|
+            readme_html_str = File.read_utf8!(readme_path)?
 
-                    example_folder_name = Str.split_on(readme_path, "/") |> List.take_last(2) |> List.first()?
-                    specific_example_link = Str.join_with([examples_repo_link, example_folder_name], "/")
-                    readme_str_edited = Str.replace_each(readme_html_str, "</h1>", """</h1><a id="gh-example-link" href="${specific_example_link}" aria-label="view on github">${github_logo_svg}</a>""")
+            example_folder_name = Str.split_on(readme_path, "/") |> List.take_last(2) |> List.first()?
+            specific_example_link = Str.join_with([examples_repo_link, example_folder_name], "/")
+            readme_str_edited = Str.replace_each(readme_html_str, "</h1>", """</h1><a id="gh-example-link" href="${specific_example_link}" aria-label="view on github">${github_logo_svg}</a>""")
 
-                    File.write_utf8!(readme_path, readme_str_edited)
-            )?
-        _ ->
-            Err(FindExamplesReadmeHtmlFailed(Inspect.to_str(find_readme_html_output)))?
+            File.write_utf8!(readme_path, readme_str_edited)
 
-    Stdout.line!("Website built in dir 'www/build'.")
\ No newline at end of file
+    ) ? |err| ExamplesReadmeReplaceFailed(err)
+
+    Stdout.line!("Website built in dir 'www/build'.")
+
+run_cmd! : Str, List Str => Result {} [BadCmdOutput(Str)]_
+run_cmd! = |cmd_str, args|
+    _ = run_cmd_w_output!(cmd_str, args)?
+
+    Ok({})
+
+run_cmd_w_output! : Str, List Str => Result Str [BadCmdOutput(Str)]_
+run_cmd_w_output! = |cmd_str, args|
+    cmd_out =
+        Cmd.new(cmd_str)
+        |> Cmd.args(args)
+        |> Cmd.output!()
+
+    stdout_utf8 = Str.from_utf8_lossy(cmd_out.stdout)
+
+    when cmd_out.status is
+        Ok(0) ->
+            Ok(stdout_utf8)
+        _ ->
+            stderr_utf8 = Str.from_utf8_lossy(cmd_out.stderr)
+            err_data =
+                """
+                Cmd ${cmd_str} ${Str.join_with(args, " ")} failed:
+                - status: ${Inspect.to_str(cmd_out.status)}
+                - stdout: ${stdout_utf8}
+                - stderr: ${stderr_utf8}
+                """
+
+            Err(BadCmdOutput(err_data))

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions