{"id":17180580,"url":"https://github.com/houzuoguo/schale","last_synced_at":"2025-04-13T16:30:27.064Z","repository":{"id":9874751,"uuid":"11875360","full_name":"HouzuoGuo/schale","owner":"HouzuoGuo","description":"A subprocess interface for Scala","archived":false,"fork":false,"pushed_at":"2015-09-16T05:09:40.000Z","size":5310,"stargazers_count":97,"open_issues_count":2,"forks_count":6,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-10-31T21:42:48.418Z","etag":null,"topics":["scala","shell"],"latest_commit_sha":null,"homepage":"","language":"Scala","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/HouzuoGuo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-08-04T07:20:47.000Z","updated_at":"2022-06-12T07:19:31.000Z","dependencies_parsed_at":"2022-09-06T05:42:00.868Z","dependency_job_id":null,"html_url":"https://github.com/HouzuoGuo/schale","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HouzuoGuo%2Fschale","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HouzuoGuo%2Fschale/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HouzuoGuo%2Fschale/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/HouzuoGuo%2Fschale/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/HouzuoGuo","download_url":"https://codeload.github.com/HouzuoGuo/schale/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223597074,"owners_count":17170872,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["scala","shell"],"created_at":"2024-10-15T00:29:54.708Z","updated_at":"2024-11-07T22:02:56.875Z","avatar_url":"https://github.com/HouzuoGuo.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"Schale\n------\n\nSchale is a subprocess interface for Scala. Make all your system programs easily available to Scala, call those programs and interact with their input and output!\n\n## Why use Schale?\n\nAlthough Scala standard library `scala.sys.process` helps external process execution, however it does not:\n\n- Manage interactive input/output\n- Manage process environment (variables and working directory)\n\nSchale addresses both of the downsides:\n\n- It supports both asynchronous and synchronous interactive IO by exposing an Akka actor, eliminating the necessity of manual stream management.\n- Process environment can be very easily managed and prepared in a hierarchical fashion, reduce code redundancy and improve readability.\n\n## Usage\n\n### A gentle start\n\n    import at.loveoneanother.schale._\n    println(Command(\"ls\", \"-l\", \"/\"))\n    println(Shell(\"ls -l /\"))\n\n`Command` runs any process, `Shell` runs system shell interpreter. The function return values have exactly the same Schale API.\n\nThis is the only use case in which `.waitFor()` call is unnecessary.\n\n### Run in background\n\n    val proc = Shell(\"sleep 100\")\n    proc.bg()\n    val exitStatus = proc.waitFor()\n\nBoth simple and interactive IO may be used on background process.\n\nProcess `.destroy()` can be used any time to destory a process before its completion, even during simple or interactive IO.\n\n### Simple IO\n\n    val grepper = Shell(\"grep Scala\")\n    grepper.input(\"Java API\\n\", \"Scala API\\n\", \"Scala Doc\\n\")\n    for (line \u003c- grepper.stdout) { println(line) }\n    for (line \u003c- grepper.stderr) { println(line) }\n    grepper.waitFor()\n\n`.input`, `.stdout` and `.stderr` may only be used once!\n\n### Advanced (interactive) IO\n\n    implicit val readTimeout = Timeout(2 seconds)\n    Shell(\"grep Scala\") interact { io =\u003e\n      // Stdin: write chars and strings\n      io ! \"Java API\"; io ! '\\n'\n      io ! \"Scala API\\n\"\n      io ! ProcStdinClose // EOF\n\n      // Stdout: read chars and strings\n      println(Await.result(io ? ProcStdoutReadChar, 2 seconds).asInstanceOf[Int].toChar)\n      println(Await.result(io ? ProcStdoutReadLine, 2 seconds).asInstanceOf[String])\n    } waitFor\n\n`interact` may be used any number of times. For reading from error output, there are `ProcStderrReadChar` and `ProcStderrReadLine`.\n\n### Process environment\n\n    // Do not import implicit default environment\n    import at.loveoneanother.schale.{ Env, Command, Shell }\n    new Env() {\n      cd(\"/\") {\n        println(Command(\"pwd\")) // root\n        env(Map(\"mylang\" -\u003e \"Scala\")) { println(Shell(\"echo $mylang\")) } // Scala\n      }\n      cd(\"/tmp\") {\n        println(Command(\"pwd\")) // tmp\n      }\n      env(Map(\"hobby\" -\u003e \"gliding\")) {\n        // Override value\n        env(Map(\"hobby\" -\u003e \"programming\")) { println(Shell(\"echo $hobby\")) } // programming\n      }\n    }\n\nStart from a `new Env()` object, use `cd()` to change directory and `env()` to add/override variables, __stack__ those calls to easily manage hierarchical process environment!\n\n## Installation\n`schale` currently uses [sbt-assembly](https://github.com/sbt/sbt-assembly)\nto produce a fat jar.\nFirst, verify `build.sbt` contains the same libraries as\nthe codebase to integrate with.\nNext, run `sbt assembly` to create `target/scala-X.XX/schale.jar`.\n\n## Some notes\n\n__Is `Shell()` cross platform?__\n\n`Comamnd()` is cross platform, however `Shell(\"script\")` assumes \\*nix OS platform and the availability of `/bin/sh`. Alternative call `Shell(\"script\", \"interpreter path\")` uses the specified interpreter, but still cannot be guaranteed to run cross-platform.\n\n__Can I `cd()` to relative paths?__\n\nIn a process environment, `cd()` call only accepts absolute path, this due to JVM's inability to determine whether a path is relative or absolute. You may find `java.nio.file.Paths` easy to work with `cd()`.\n\n__Can I use Schale to interact with SSH/SFTP/SCP?__\n\nJVM cannot interact with TTY and Schale itself is not a terminal emulator, therefore it cannot be used on programs which require advanced terminal features, such as SSH/SFTP/SCP. Sorry!\n\n## Version History\n\n\u003ctable\u003e\n\u003ctr\u003e\n  \u003cth\u003eVersion\u003c/th\u003e\n  \u003cth\u003eBranch\u003c/th\u003e\n  \u003cth\u003eRelease Date\u003c/th\u003e\n  \u003cth\u003eComment\u003c/th\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n  \u003ctd\u003eAlpha\u003c/td\u003e\n  \u003ctd\u003ealpha\u003c/td\u003e\n  \u003ctd\u003e2013-08-10\u003c/td\u003e\n  \u003ctd\u003eFirst release\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n## Contact and License\n\nYou may want to check out [Issues] section for future plans, and please feel very free to contact [Howard] if you have any feedback / questions. I also have [Twitter] and [blog], please check them out as well.\n\nThe following copyright notice and disclaimers apply to all files in the project repository:\n\u003cpre\u003e\nCopyright (c) 2013, Howard Guo\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\u003c/pre\u003e\n\n## Project Background\n\nSubprocess management was traditionally carried out by using `Runtime.getRuntime().exec` series of calls. Although JDK introduced `ProcessBuilder` later on, but process building and IO interactivity could still be cumbersome.\n\nSchale takes advantage of advanced features and syntactic sugar offered by Scala, and brings to you:\n\n- Easy process creation\n- Background process management\n- Simplified process input/output interface\n- Advanced, interactive, non-blocking process IO\n- Hierarchical process environment (variables, working directory) management\n\nSchale was inspired by Python third-party package \"sh\".\n\n[Howard]: mailto:guohouzuo@gmail.com\n[Twitter]: https://twitter.com/hzguo\n[blog]: http://allstarnix.blogspot.com.au\n[Issues]: https://github.com/HouzuoGuo/schale/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhouzuoguo%2Fschale","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhouzuoguo%2Fschale","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhouzuoguo%2Fschale/lists"}