-
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.
feat: add an implementation of the CliTool traits (#1)
Co-authored-by: Fang Yin Lo <[email protected]>
- Loading branch information
Showing
17 changed files
with
900 additions
and
4 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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,43 @@ | ||
name: Unit Tests | ||
|
||
on: [ push, pull_request ] | ||
|
||
jobs: | ||
unit-tests: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
suite: [ clitool ] | ||
java-version: [ 11, 17, 21 ] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- uses: actions/setup-java@v4 | ||
with: | ||
distribution: 'temurin' | ||
java-version: ${{ matrix.java-version }} | ||
- name: Cache for Scala Dependencies | ||
uses: actions/cache@v4 | ||
with: | ||
path: | | ||
~/.mill/download | ||
~/.m2/repository | ||
~/.cache/coursier | ||
key: ${{ runner.os }}-java-mill-${{ matrix.java-version }}-${{ hashFiles('**/build.sc') }} | ||
restore-keys: ${{ runner.os }}-java-mill- | ||
- name: Compile Scala Code | ||
run: | | ||
./mill --no-server clean | ||
./mill --no-server --disable-ticker ${{ matrix.suite }}.compile | ||
- name: Test Scala Code | ||
run: | | ||
./mill --no-server --disable-ticker ${{ matrix.suite }}.test | ||
- name: Create Code Coverage Report | ||
if: matrix.java-version == '11' | ||
run: | | ||
./mill --no-server --disable-ticker ${{ matrix.suite }}.scoverage.htmlReport | ||
- name: Upload Code Coverage Report | ||
uses: actions/upload-artifact@v4 | ||
if: matrix.java-version == '11' | ||
with: | ||
name: code-coverage | ||
path: out/clitool/scoverage/htmlReport.dest/ |
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 |
---|---|---|
@@ -1,5 +1,13 @@ | ||
.bsp/* | ||
.DS_Store | ||
.idea/* | ||
.java-version | ||
.metals/* | ||
.vscode/* | ||
*.class | ||
*.log | ||
|
||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
**/*.iml | ||
bin/* | ||
hs_err_pid* | ||
out/* | ||
target/* |
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 @@ | ||
0.12.3 |
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 |
---|---|---|
@@ -1,2 +1,34 @@ | ||
# clitool | ||
A small set of Scala traits to help execute command line tools | ||
|
||
[![Unit Tests](https://github.com/clintval/clitool/actions/workflows/unit-tests.yml/badge.svg?branch=main)](https://github.com/clintval/clitool/actions/workflows/unit-tests.yml?query=branch%3Amain) | ||
[![Java Version](https://img.shields.io/badge/java-11,17,21-c22d40.svg)](https://github.com/AdoptOpenJDK/homebrew-openjdk) | ||
[![Language](https://img.shields.io/badge/language-scala-c22d40.svg)](https://www.scala-lang.org/) | ||
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/clintval/clitool/blob/master/LICENSE) | ||
|
||
A small set of Scala traits to help execute command line tools. | ||
|
||
![Cisco and the Grand Canyon](.github/img/cover.jpg) | ||
|
||
```scala | ||
val ScriptResource = "io/cvbio/io/CliToolTest.py" | ||
|
||
Python3.execScript( | ||
scriptResource = ScriptResource, | ||
args = Seq.empty, | ||
logger = Some(logger), | ||
stdoutRedirect = logger.info, | ||
stderrRedirect = logger.warning, | ||
) | ||
``` | ||
|
||
#### If Mill is your build tool | ||
|
||
```scala | ||
ivyDeps ++ Agg(ivy"io.cvbio.io::clitool::0.1.0") | ||
``` | ||
|
||
#### If SBT is your build tool | ||
|
||
```scala | ||
libraryDependencies += "io.cvbio.io" %% "clitool" % "0.1.0" | ||
``` |
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,110 @@ | ||
import $ivy.`com.lihaoyi::mill-contrib-scoverage:$MILL_VERSION` | ||
import coursier.maven.MavenRepository | ||
import mill._ | ||
import mill.api.JarManifest | ||
import mill.contrib.scoverage.ScoverageModule | ||
import mill.define.{Target, Task} | ||
import mill.scalalib._ | ||
import mill.scalalib.publish._ | ||
|
||
import java.util.jar.Attributes.Name.{IMPLEMENTATION_VERSION => ImplementationVersion} | ||
|
||
/** The official package version. */ | ||
private val packageVersion = "0.1.0" | ||
|
||
/** A base trait for all test targets. */ | ||
trait ScalaTest extends TestModule { | ||
|
||
/** The dependencies needed only for tests. */ | ||
override def ivyDeps = Agg( | ||
ivy"ch.qos.logback:logback-classic:1.5.12", | ||
ivy"org.scalatest::scalatest::3.2.19".excludeOrg(organizations = "org.junit"), | ||
) | ||
|
||
/** The test framework to use for this project. */ | ||
override def testFramework: Target[String] = T { "org.scalatest.tools.Framework" } | ||
} | ||
|
||
/** The clitool Scala package package. */ | ||
object clitool extends ScalaModule with PublishModule with ScoverageModule { | ||
object test extends ScalaTests with ScalaTest with ScoverageTests | ||
|
||
def scalaVersion = "2.13.14" | ||
def scoverageVersion = "2.1.1" | ||
def publishVersion = T { packageVersion } | ||
|
||
/** POM publishing settings for this package. */ | ||
def pomSettings: Target[PomSettings] = PomSettings( | ||
description = "A small set of Scala traits to help execute command line tools.", | ||
organization = "io.cvbio.io", | ||
url = "https://github.com/clintval/clitool", | ||
licenses = Seq(License.MIT), | ||
versionControl = VersionControl.github(owner = "clintval", repo = "clitool", tag = Some(packageVersion)), | ||
developers = Seq( | ||
Developer(id = "clintval", name = "Clint Valentine", url = "https://github.com/clintval"), | ||
Developer(id = "fangylo", name = "Fang Yin Lo", url = "https://github.com/fangylo"), | ||
) | ||
) | ||
|
||
/** The artifact name, fully resolved within the coordinate. */ | ||
override def artifactName: T[String] = T { "clitool" } | ||
|
||
/** The JAR manifest. */ | ||
override def manifest: T[JarManifest] = super.manifest().add(ImplementationVersion.toString -> packageVersion) | ||
|
||
/** The dependencies of the project. */ | ||
override def ivyDeps = Agg( | ||
ivy"org.slf4j:slf4j-nop:1.7.6", | ||
ivy"org.scala-lang.modules::scala-parallel-collections::1.0.0", | ||
) | ||
|
||
/** All the repositories we want to pull from. */ | ||
override def repositoriesTask: Task[Seq[coursier.Repository]] = T.task { | ||
super.repositoriesTask() ++ Seq(MavenRepository("https://oss.sonatype.org/content/repositories/public")) | ||
} | ||
|
||
/** All Scala compiler options for this package. */ | ||
override def scalacOptions: T[Seq[String]] = T { | ||
Seq( | ||
"-opt:inline:io.cvbio.**", // Turn on the inliner. | ||
"-opt-inline-from:io.cvbio.**", // Tells the inliner that it is allowed to inline things from these classes. | ||
"-Yopt-log-inline", "_", // Optional, logs the inliner activity so you know it is doing something. | ||
"-Yopt-inline-heuristics:at-inline-annotated", // Tells the inliner to use your `@inliner` tags. | ||
"-opt-warnings:at-inline-failed", // Tells you if methods marked with `@inline` cannot be inlined, so you can remove the tag. | ||
// The following are sourced from https://nathankleyn.com/2019/05/13/recommended-scalac-flags-for-2-13/ | ||
"-deprecation", // Emit warning and location for usages of deprecated APIs. | ||
"-explaintypes", // Explain type errors in more detail. | ||
"-feature", // Emit warning and location for usages of features that should be imported explicitly. | ||
"-unchecked", // Enable additional warnings where generated code depends on assumptions. | ||
"-Xcheckinit", // Wrap field accessors to throw an exception on uninitialized access. | ||
"-Xfatal-warnings", // Fail the compilation if there are any warnings. | ||
"-Xlint:adapted-args", // Warn if an argument list is modified to match the receiver. | ||
"-Xlint:constant", // Evaluation of a constant arithmetic expression results in an error. | ||
"-Xlint:delayedinit-select", // Selecting member of DelayedInit. | ||
"-Xlint:doc-detached", // A Scaladoc comment appears to be detached from its element. | ||
"-Xlint:inaccessible", // Warn about inaccessible types in method signatures. | ||
"-Xlint:infer-any", // Warn when a type argument is inferred to be `Any`. | ||
"-Xlint:missing-interpolator", // A string literal appears to be missing an interpolator id. | ||
"-Xlint:nullary-unit", // Warn when nullary methods return Unit. | ||
"-Xlint:option-implicit", // Option.apply used implicit view. | ||
"-Xlint:package-object-classes", // Class or object defined in package object. | ||
"-Xlint:poly-implicit-overload", // Parameterized overloaded implicit methods are not visible as view bounds. | ||
"-Xlint:private-shadow", // A private field (or class parameter) shadows a superclass field. | ||
"-Xlint:stars-align", // Pattern sequence wildcard must align with sequence component. | ||
"-Xlint:type-parameter-shadow", // A local type parameter shadows a type already in scope. | ||
"-Ywarn-dead-code", // Warn when dead code is identified. | ||
"-Ywarn-extra-implicit", // Warn when more than one implicit parameter section is defined. | ||
"-Ywarn-numeric-widen", // Warn when numerics are widened. | ||
"-Ywarn-unused:implicits", // Warn if an implicit parameter is unused. | ||
"-Ywarn-unused:imports", // Warn if an import selector is not referenced. | ||
"-Ywarn-unused:locals", // Warn if a local definition is unused. | ||
"-Ywarn-unused:params", // Warn if a value parameter is unused. | ||
"-Ywarn-value-discard", // Warn when non-Unit expression results are unused. | ||
"-Ywarn-unused:patvars", // Warn if a variable bound in a pattern is unused. | ||
"-Ywarn-unused:privates", // Warn if a private member is unused. | ||
"-Ybackend-parallelism", Math.min(Runtime.getRuntime.availableProcessors(), 8).toString, // Enable parallelization — scalac max is 16. | ||
"-Ycache-plugin-class-loader:last-modified", // Enables caching of classloaders for compiler plugins | ||
"-Ycache-macro-class-loader:last-modified", // and macro definitions. This can lead to performance improvements. | ||
) | ||
} | ||
} |
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,30 @@ | ||
package io.cvbio.io | ||
|
||
import java.io.{Closeable, InputStream} | ||
import java.util.concurrent.atomic.AtomicInteger | ||
|
||
import scala.io.Source | ||
|
||
/** Companion object for [[AsyncStreamSink]]. */ | ||
private[io] object AsyncStreamSink { | ||
private val n: AtomicInteger = new AtomicInteger(1) | ||
private def nextName: String = s"AsyncStreamSinkThread-${n.getAndIncrement}" | ||
} | ||
|
||
/** Non-blocking class that will read output from a stream and pass it to a sink. */ | ||
private[io] class AsyncStreamSink(in: InputStream, private val sink: String => Unit) extends Closeable { | ||
private val source = Source.fromInputStream(in).withClose(() => in.close()) | ||
private val thread = new Thread(() => source.getLines().foreach(sink)) | ||
this.thread.setName(AsyncStreamSink.nextName) | ||
this.thread.setDaemon(true) | ||
this.thread.start() | ||
|
||
/** Give the thread 500 seconds to wrap up what it's doing and then interrupt it. */ | ||
def close() : Unit = close(500) | ||
|
||
/** Give the thread `millis` milliseconds to finish what it's doing, then interrupt it. */ | ||
def close(millis: Long) : Unit = { | ||
this.thread.join(millis) | ||
this.thread.interrupt() | ||
} | ||
} |
Oops, something went wrong.