I have a sbt project that includes code generation.
Part of the build.sbt is
lazy val generator = (project in file("generator")).
settings(mainClass := Some("com.example.Generator"))
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration)
def runGeneration: SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val cachedFun = FileFunction.cached(
streams.value.cacheDirectory / "generation"
) { (in: Set[File]) =>
val dir = (sourceManaged in Compile).value
(generator / run in Compile).toTask(" " + dir.getAbsolutePath).value
collectFiles(dir)
}
val dependentFiles = ((generator / fullClasspath in Compile) map { cp => cp.files }).taskValue.value
val genFiles = cachedFun(dependenctFiles).toSeq
Def.task {
genFiles
}
}.taskValue
This seems to work and only generate files when a dependency has changed. However, I expect to have multiple generators. Rather than copy the code, I attempted to pass the generator project to it:
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration(generator))
def runGeneration(p: project): SettingsDefinition =
<same as before but with p instead of generator>
This results in an error parsing the build file:
build.sbt:155: error: Illegal dynamic reference: File
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue.value
^
[error] sbt.compiler.EvalException: Type error in expression
[error] sbt.compiler.EvalException: Type error in expression
I am guessing the problem is that it cannot figure out at compile time if there is a dependency loop, so it convervatively gives an error.
Is there a way to get this to work? Is there an entirely different construct that lets me know if running generator will produce a different result?
The underlying problem is that task definitions in sbt have two components, which look like they can be intermingled, but cannot. If you write code like
Def.task {
val doIt = checkIfShouldDoIt()
if (doIt) {
someTask.value
} else {
()
}
}
this naively looks like it will only run someTask if doIt is true. What actually happens is that someTask.value declares a dependency of this task on someTask and someTask is run before anything is done for this task. To write the above code in a way that more directly maps to what actually happens, one would write
Def.task {
val someTaskValue = someTask.value
val doIt = checkIfShouldDoIt()
if (doIt) {
someTaskValue
} else {
()
}
}
The attempt to run the task only when the dependencies had changed could not work in a single task.
My working solution does the following. I modified the generator to take an additional argument and do nothing if that argument was false. The two tasks were
// Task to check if we need to generate
def checkGeneration(p: Project) = Def.taskDyn {
var needToGenerate = false
val cachedFunction = FileFunction.cached(someDir) {
(in: Set[File]) =>
needToGenerate = ! in.isEmpty
Set()
}
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue
Def.task {
cachedFun(dependentFiles.value.toSet)
needToGenerate
}
}
// Task to run generation
def runGeneration(p: Project): SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val needToGenerate = checkGeneration(p).value
Def.task {
// Run generator as before but pass needToGenerate as additional argument
...
// Used FileFunction.cached as before to find the generated files (but not run the generator)
...
}
}
It is possible that I have more dynamic tasks than I need, but this works.
I want to daemonize myapp but I have one big problem. The channels I'm using are of type chan struct{}.
However, with the package getopt (flag package), my flags are of type *bool, so I don't know how can I modify myapp.
It's not enough with channels type bool. I'm sure there are a concept that I don't understand. I attach you the code:
package main
import (
"os"
"syscall"
"time"
"github.com/pborman/getopt/v2"
"github.com/sevlyar/go-daemon"
)
var (
done = make(chan struct{})
optQuit = make(chan struct{})
optRun = make(chan struct{})
)
func TermHandler(sig os.Signal) error {
optQuit <- struct{}{}
if sig == syscall.SIGQUIT {
<-done
}
return nil
}
func main() {
optHelp := getopt.BoolLong("help", 'h', "Help")
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")
if *optHelp {
getopt.Usage()
os.Exit(0)
}
// Create pid file
cntxt := &daemon.Context{
PidFileName: "/var/run/myapp.pid",
PidFilePerm: 0644,
WorkDir: "./",
Umask: 027,
Args: []string{"[Z]"},
}
if len(daemon.ActiveFlags()) > 0 {
d, _ := cntxt.Search()
daemon.SendCommands(d)
return
}
d, err := cntxt.Reborn()
if d != nil {
return
}
if err != nil {
os.Exit(1)
}
defer cntxt.Release()
// Define ticker
ticker := time.NewTicker(time.Second)
myapp := true
// Loop
for myapp {
select {
// Case sleep
case <- ticker.C:
time.Sleep(time.Second)
// Case QUIT
case <- optQuit:
done <- struct{}{}
myapp = false
ticker.Stop()
os.Exit(0)
// Case RUN
case <- optRun:
// Executes a goroutine...
}
}
}
With go install, I can see this errors:
./main.go:72: invalid operation: <-optQuit (receive from non-chan type *bool)
./main.go:79: invalid operation: <-optRun (receive from non-chan type *bool)
I don't know how I should modify the channels (done, optQuit of type struct{}), to resolve this...
P.S.: I show you an example that I did. It runs as daemon and each minute, it executes the function Writer().
After, if you type zdaemon -z quit, the app does a graceful shutdown. You can run it in your machines:
https://play.golang.org/p/RVq7M7usEj
Those two lines in your main function shadow your global variable declaration:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")
If you only use them, to get a nice usage, why not create a usage function
yourself?
If you insist on using getopt just to create a usage, do
_ = getopt.BoolLong("quit", 0, "Help")
_ = getopt.BoolLong("run", 'r', "Help")
instead.
You also need to call getopt.Parse() before using *optHelp.
The resulting message
Usage: test [-hr] [--quit] [parameters ...]
-h, --help Help
--quit Help
-r, --run Help
seems to be less than helpful. Why not just do
fmt.Printf(`
Usage: test
This program will start a daemon service, which you can use like this ...
`)
You define optQuit = make(chan struct{}) globally and then shadow it in main: optQuit := getopt.BoolLong("quit", 0, "Help").
So in main optQuit is a bool, not a chan
Remove those two lines in main:
optQuit := getopt.BoolLong("quit", 0, "Help")
optRun := getopt.BoolLong("run", 'r', "Help")
I have "Common.scala" in project dir:
import sbt.Keys._
import sbt._
import bintray.BintrayKeys._
object Common {
val commonSettings = Seq(
organization := "com.github.kondaurovdev",
scalaVersion := "2.11.8",
scalacOptions ++= Seq("-unchecked", "-deprecation", "-feature"),
publishLocal := (),
parallelExecution := false
)
val doNotPublishSettings = Seq(
publish := {},
publishLocal := {}
)
def getPublishSettings(_version: String) = {
if (_version.endsWith("-SNAPSHOT")) {
{
println("is snapshot!")
Seq(
publishTo := Some("Artifactory Realm" at "http://oss.jfrog.org/artifactory/oss-snapshot-local"),
bintrayReleaseOnPublish := false,
credentials := List(Path.userHome / ".bintray" / ".artifactory").filter(_.exists).map(Credentials(_))
)
}
} else {
{
println("is release")
Seq(
bintrayOmitLicense := true,
bintrayRepository := "maven",
publishArtifact in Test := false,
pomExtra :=
<developers>
<developer>
<id>kondaurovdev</id>
<name>Alexander Kondaurov</name>
<email>kondaurov.dev#gmail.com</email>
</developer>
</developers>
)
}
} ++ Seq(
licenses += ("MIT", url("http://opensource.org/licenses/MIT"))
)
}
def myProject(name: String, _version: String = "0.1.1-SNAPSHOT", deps: Seq[ModuleID] = Seq(), settings: Seq[Def.SettingsDefinition] = Seq(), path: Option[String] = None): Project = {
Project(name, file(path.getOrElse(name)))
.settings(
commonSettings ++
getPublishSettings(_version)
)
.settings(
libraryDependencies ++= deps,
version := _version
)
.settings(
settings: _*
)
}
}
And i have thus projects in "build.sbt":
lazy val snippets: Project = {
Common.myProject("snippets", deps = Seq(
Deps.specs2,
Deps.Log.slf4j
))
}
When i try "snippets/publish" i get this errors:
> snippets/publish
[info] Wrote /Users/alexanderkondaurov/Projects/kondaurov/scala/snippets/target/scala-2.11/snippets_2.11-0.1-SNAPSHOT.pom
[info] :: delivering :: com.github.kondaurovdev#snippets_2.11;0.1-SNAPSHOT :: 0.1-SNAPSHOT :: integration :: Sat Jan 21 14:42:01 MSK 2017
[info] delivering ivy file to /Users/alexanderkondaurov/Projects/kondaurov/scala/snippets/target/scala-2.11/ivy-0.1-SNAPSHOT.xml
[error] Unable to find credentials for [Artifactory Realm # oss.jfrog.org].
[trace] Stack trace suppressed: run last snippets/*:bintrayEnsureLicenses for the full output.
[trace] Stack trace suppressed: run last snippets/*:publish for the full output.
[error] (snippets/*:bintrayEnsureLicenses) you must define at least one license for this project. Please choose one or more of
[error] AFL-3.0, AGPL-V3, APL-1.0, APSL-2.0, Apache-1.0, Apache-1.1, Apache-2.0, Artistic-License-2.0, Attribution, BSD, BSD New, BSD Simplified, BSL-1.0, Bouncy-Castle, CA-TOSL-1.1, CDDL-1.0, CPAL-1.0, CPL-1.0, CPOL-1.02, CUAOFFICE-1.0, Codehaus, Day, Day-Addendum, ECL2, EUDATAGRID, EUPL-1.1, Eclipse-1.0, Eiffel-2.0, Entessa-1.0, Fair, Frameworx-1.0, GPL-2.0, GPL-2.0+CE, GPL-3.0, HSQLDB, Historical, IBMPL-1.0, IPAFont-1.0, ISC, IU-Extreme-1.1.1, JA-SIG, JSON, JTidy, LGPL-2.1, LGPL-3.0, Lucent-1.02, MIT, MPL-2.0, MS-PL, MS-RL, MirOS, Motosoto-0.9.1, Mozilla-1.1, Multics, NASA-1.3, NAUMEN, NOSL-3.0, NTP, Nethack, Nokia-1.0a, OCLC-2.0, OSL-3.0, Openfont-1.1, Opengroup, PHP-3.0, PostgreSQL, Public Domain, Public Domain - SUN, PythonPL, PythonSoftFoundation, QTPL-1.0, RPL-1.5, Real-1.0, RicohPL, SUNPublic-1.0, SimPL-2.0, Sleepycat, Sybase-1.0, TMate, Unlicense, UoI-NCSA, VovidaPL-1.0, W3C, WTFPL, Xnet, ZLIB, ZPL-2.0, wxWindows
[error] (snippets/*:publish) java.io.IOException: Access to URL http://oss.jfrog.org/artifactory/oss-snapshot-local/com/github/kondaurovdev/snippets_2.11/0.1-SNAPSHOT/snippets_2.11-0.1-SNAPSHOT.pom was refused by the server: Unauthorized
[error] Total time: 2 s, completed Jan 21, 2017 2:42:03 PM
>
I don't get it why it complains about license, i've included MIT license..
I followed by this article: http://szimano.org/automatic-deployments-to-jfrog-oss-and-bintrayjcentermaven-central-via-travis-ci-from-sbt/
ADDED:
I fixed this license issue by moving
"licenses += ("MIT", url("http://opensource.org/licenses/MIT"))" right after "credentials += ..."
now it look like:
Seq(
publishTo := Some("Artifactory Realm" at "https://oss.jfrog.org/artifactory/oss-snapshot-local"),
bintrayReleaseOnPublish := false,
credentials := List(Path.userHome / ".bintray" / ".artifactory").filter(_.exists()).map(Credentials(_)),
licenses += ("MIT", url("http://opensource.org/licenses/MIT"))
)
That's strange.. Credentials file looks like:
realm = Artifactory Realm
host = oss.jfrog.org
user = *********
password = ***********
And i understood that in order to upload snapshots package it has to be approved by making request to support service. They will create folder for your package. This procedure needs to be done for for every package, are you kidding guys?
I have an account here "https://oss.sonatype.org/". I've there namespace and can upload as many packages as i need, i've expected the same behaviour in OJO. I'm not making approve request to support service every time when i've new package
Setting credentials in ~/.sbt/ is the way forward. Credentials can be in the build.sbt, however username, password is left in plaintext as well as ip address of repository sever.
To set credentials via a configuration file you can use:
credentials += Credentials(Path.userHome / ".sbt" / ".credentials")
This picks up credentials in a file called .credentials which is stored in my ~/.sbt/ dir.
To set credentials in the Credentials obj you can use something like:
credentials += Credentials("Artifactory Realm", "http://<ip>:<port>/artifactory/<repo-key>", "<username>", "<password>")
It's also important to make sure that publishTo has been set with the relevant resolver. An example of which is:
publishTo := Some("Artifactory Realm" at "http://<ip>:<port>/artifactory/<repo-key>
To configure a proxy. The following can be added to a file called repositories stored in ~/.sbt/. An example configuration may look like this:
[repositories]
local
my-ivy-proxy-releases: http://<host>:<port>/artifactory/<repo-key>/, [organization]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)[revision]/[type]s/[artifact](-[classifier]).[ext]
my-maven-proxy-releases: http://<host>:<port>/artifactory/<repo-key>/
What are the means of redirecting output from a single command to a file in sbt?
I could exit sbt, execute sbt mycommand > out.txt, and start it again, but I'm wondering if there's an alternative?
In Add a custom logger you can find more information about what's required to have a custom logger that logs to a file - use extraLoggers and add an instance of sbt.AbstractLogger that does the saving.
You may find my answer to Displaying timestamp for debug mode in SBT? useful. The example copied here:
def datedPrintln = (m: String) =>
println(s"+++ ${java.util.Calendar.getInstance().getTime()} $m")
extraLoggers := {
val clientLogger = FullLogger {
new Logger {
def log(level: Level.Value, message: => String): Unit =
if(level >= Level.Info) datedPrintln(s"$message at $level")
def success(message: => String): Unit = datedPrintln(s"success: $message")
def trace(t: => Throwable): Unit = datedPrintln(s"trace: throwable: $t")
}
}
val currentFunction = extraLoggers.value
(key: ScopedKey[_]) => clientLogger +: currentFunction(key)
}
I have created a web service using ASP.NET.
I tried to access this url from a PL/sql program through UTL_DBWS package. After execution i am receiving below error:
ORA-29532: Java call terminated by uncaught Java exception: port: {http://tempuri.org/}Service1Soap
does not contain operation: Envelope
Can any one of you please tell what steps of configuration I am missing.
I really apprcite your help.
Oracle procedure to call to asp.net service is :
create or replace procedure check_dbws
AS
l_service UTL_DBWS.service;
l_call UTL_DBWS.call;
l_wsdl_url VARCHAR2(32767);
l_namespace VARCHAR2(32767);
l_service_qname UTL_DBWS.qname;
l_port_qname UTL_DBWS.qname;
l_operation_qname UTL_DBWS.qname;
l_xmltype_in SYS.XMLTYPE;
l_xmltype_out SYS.XMLTYPE;
p_fault_node xmltype;
l_return NUMBER;
l_int_type utl_dbws.qname;
l_string_type utl_dbws.QNAME;
BEGIN
l_wsdl_url := 'http://localhost/TestWebService/Service1.asmx?wsdl';
l_namespace := 'http://tempuri.org/';
l_service_qname := UTL_DBWS.to_qname(l_namespace, 'Service1');
l_port_qname := UTL_DBWS.to_qname(l_namespace, 'Service1Soap');
l_operation_qname := UTL_DBWS.to_qname(l_namespace, 'DBConnect');
l_service := UTL_DBWS.create_service (
wsdl_document_location => URIFACTORY.getURI(l_wsdl_url),
service_name => l_service_qname);
l_call := UTL_DBWS.create_call (
service_handle => l_service,
port_name => l_port_qname,
operation_name => l_operation_qname);
utl_dbws.set_property (l_call,'SOAPACTION_USE','TRUE');
utl_dbws.set_property (l_call,'SOAPACTION_URI', 'DBConnect');
utl_dbws.set_property(l_call,'ENCODINGSTYLE_URI', 'http://schemas.xmlsoap.org/soap/encoding/');
utl_dbws.set_property(l_call,'OPERATION_STYLE', 'document');
l_string_type :=utl_dbws.to_qname('http://www.w3.org/2001/xmlschema','String');
utl_dbws.add_parameter(l_call,'Request',l_string_type,'ParameterMode.IN');
utl_dbws.set_return_type(l_call,l_string_type);
l_xmltype_in:=sys.xmltype('<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v002="http://tempuri.org/DBConnect">
<soapenv:Header/>
<soapenv:Body>
<DBConnect>
<Name>Test</Name>
<DBConnect>
</soapenv:Body>
</soapenv:Envelope>');
l_xmltype_out := UTL_DBWS.invoke (call_handle => l_call,,request => l_xmltype_in);
p_fault_node := l_xmltype_out.extract('//soap:Fault', 'xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/');
if (p_fault_node is not null) then
dbms_output.put_line(p_fault_node.getclobval());
l_return:=2;
elsif l_xmltype_out is not null then
dbms_output.put_line(l_xmltype_out.getclobval());
l_return:=1;
else
dbms_output.put_line('errorin fault'||sqlerrm);
l_return:=0;
end if;
UTL_DBWS.release_call (call_handle => l_call);
UTL_DBWS.release_service (service_handle => l_service);
dbms_output.put_line(l_result.AccessVarchar2);
END;
have a look at my answer here; you may not have all the Java classes required to get UTL_DBWS to work. And, per my answer there, I'll reiterate, I found it much easier to use UTL_HTTP than UTL_DBWS and continue to use UTL_HTTP since I ran into so many limitations and issues with UTL_DBWS.