From my testing, both
task taskA {
doFirst {
println("$name first")
}
doLast {
println("$name second")
}
}
and
task taskB {
doLast {
println("$name first")
println("$name second")
}
}
executes in the same order.
What is the significance of having a separate doFirst block? Can something else happen between the execution of doFirst and doLast?
I have gone through the gradle docs section on tasks. The examples also seem to use just doLast
Related
I am working with callBack flow to observe a Firestore document. My flow needs to throw ResourceNotFoundException when the document being watched gets moved or deleted by some other person using the app. Below is my code for the flow
fun observeDocument(collectionId: String, documentId: String) = callbackFlow {
database.collection(collectionId).document(documentId)
.addSnapshotListener { documentSnapshot, firebaseFireStoreException ->
if (firebaseFireStoreException != null)
throw firebaseFireStoreException
if (documentSnapshot == null || !documentSnapshot.exists()) {
throw ResourceNotFoundException("")
}
try {
offer(documentSnapshot.toObject(PrintOrder::class.java))
} catch (e: Exception) {
}
}
awaitClose { }
}
and I am collecting the above flow in the ViewModel by using the following code
viewModelScope.launch {
repository.observeDocument(collectionId, documentId)
.catch {e->
_loadedPrintOrder.value = LoadingStatus.Error(e)
}
.onStart {
_loadedPrintOrder.value = LoadingStatus.Loading(application.getString(R.string.one_moment_please))
}
.collect {
_loadedPrintOrder.value = LoadingStatus.Success(it!!)
}
}
Now, the problem is catch operator is not catching the exception thrown from the flow (ResourceNotFoundException). I have even tried wrapping the flow collection code inside a try-catch block. Even the try-catch block fails to catch the exception and the app crashes.
How can I catch the Exception which is thrown from the callBackFlow during collection of the flow?
The catch operator catches exceptions in the flow completion. It will catch only if the flow completes normally or exceptionally. As you saw, it will never be thrown inside a flow builder. Moreover, your flow never completes since you are using awaitClose to keep him alive.
Since this builder uses a Channel under the hood, you can close it manually with non-null cause in order to complete the flow exceptionally:
abstract fun close(cause: Throwable? = null): Boolean
So you can use a try/catch inside the callbackFlow builder to close it manually as follows:
database.collection(collectionId)
.document(documentId)
.addSnapshotListener { documentSnapshot, firebaseFireStoreException ->
try {
if (firebaseFireStoreException != null)
throw firebaseFireStoreException
if (documentSnapshot == null || !documentSnapshot.exists()) {
throw ResourceNotFoundException("Oops!")
}
offer(documentSnapshot.toObject(PrintOrder::class.java))
} catch (e: Exception) {
close(e) // close the flow with a non-null cause
}
}
With this, you should be able to catch exceptions as your firebaseFireStoreException, ResourceNotFoundException or any other one inside the catch operator because the flow is now completed exceptionally.
I am writing a connector for Google Data Studio. I want to make a new line in the exception, but it does not work. Here is the code (look getConfig):
function getData(request) {
return {};
}
function isAdminUser() {
return true;
}
function getConfig(params) {
throw("1st line\n2nd line<br>3rd line");
var cc = DataStudioApp.createCommunityConnector();
var config = cc.getConfig();
return config.build();
}
function getAuthType() {
return false;
}
function getSchema(request) {
return {
'schema' :
[
{
name: "Field_1",
dataType: 'STRING',
semantics: {
conceptType: 'DIMENSION'
}
}
]
}
}
And that's what happens (all in one line):
How do I make a new line in the exception?
Formatting the exception text is not supported. If you need additional information about exceptional behavior, Александр Ермолин is correct in suggesting logging. See Apps Script Logging for details on how to add logging to a connector.
Too much information about conditions tasks inside pipes (e. g. "gulp-if" plugin). However, actually it is not "conditional tasks": it is the "conditional plugin usage", and one task can use multiple plugins. Here is how to conditionally run task NOT inside pipe (for example, inside gulp.paralell())
Suppose that task name can contain spaces for providing easy-to-understand task meaning.
gulp.task('Build', gulp.paralell(
'Preprocess HTML',
'Prepeocess styles',
done => {
if(checkSomeCondition()){
runTask('some Task') // but how?
}
else {
done();
}
}
))
The beauty of gulp4.0 is that your tasks can just be functions, so the following works:
gulp.task('Preprocess HTML', function () {
console.log("in Preprocess HTML");
return gulp.src('./');
});
You can use either the above version (the 'old way') or the newer
way below.
I show two tasks here that use both versions but I personally wouldn't mix them.
// function PreprocessHTML() {
// console.log("in Preprocess HTML");
// return gulp.src('./');
// }
function PreprocessStyles() {
console.log("in Preprocess styles");
return gulp.src('./');
}
function testTaskTrue() {
console.log("in testTaskTrue");
return gulp.src('./');
}
function testTaskFalse() {
console.log("in testTaskFalse");
return gulp.src('./');
}
function checkSomeCondition() {
console.log("in checkSomeCondition");
return false;
}
// Again, I definitely wouldn't mix the two versions of tasks as shown below.
// Just here for demonstration purposes.
gulp.task('test', gulp.parallel( 'Preprocess HTML', PreprocessStyles,
done => {
if (checkSomeCondition()) {
// so testTaskTrue can be any gulp4.0 task, easy to call since it just a function
testTaskTrue();
}
else {
testTaskFalse();
}
done();
}
));
For gulp 4, first create this helper function:
function gulpTaskIf(condition, task) {
task = gulp.series(task) // make sure we have a function that takes callback as first argument
return function (cb) {
if (condition()) {
task(cb)
} else {
cb()
}
}
}
As its first argument, this helper takes a condition in the form of a function. The condition function is run at the time when the task execution is to start, so you can i.e. check output of previous steps in the condition function.
The second arguments specifies the task to be run and can be the same values that gulp.parallel() or gulp.series() accept as arguments, i.e. string, function reference, or a return value from another gulp.parallel() or gulp.series().
Returns a function that can be passedto gulp.task() as second argument or as an argument to gulp.parallel() or gulp.series() call.
Examples (first one matches question):
embedded in e.g. gulp.parallel() or gulp.series(), calling task by name
gulp.task('Build', gulp.parallel(
'Preprocess HTML',
'Prepeocess styles',
runTaskIf(checkSomeCondition, 'some Task')
))
as a task, calling task by name
function myTask() {
return gulp.src(...)
...
.dest(...)
}
gulp.task('my-task', myTask)
gulp.task('default', gulpTaskIf(
function () {
return Math.random() < 0.5; // example condition
},
'my-task')
as a standalone task, calling task by function reference
function myTask() {
return gulp.src(...)
...
.dest(...)
}
gulp.task('default', gulpTaskIf(() => Math.random() < 0.5, myTask)
as a standalone task, calling gulp.parallel() or gulp.series() reference
const manyTasks = gulp.parallel(task1, task2, task3)
gulp.task('default', gulpTaskIf(
function () {
return Math.random() < 0.5;
},
manyTasks)
It is really simple. No need of helper function:
gulp.task('Build', function() {
const tasks = ['Preprocess HTML', 'Preprocess styles'];
if(checkSomeCondition()) tasks.push('some Task');
return gulp.parallel(tasks);
}());
The clue is in calling the function at the last line - it will return an adjusted gulp.parallel task - I am using this to handle command line arguments (yargs)
WARNING: this will be executed before the first task is executed and will be executed also when other task than 'Build' is run. Just have it on your mind when implementing logic ;)
I have an array for plugins where I do a simple If query and then expand the array, see line 280 here.
Based on Gulp 4.
For the build process I changed the Const to Let and also queried it with If.
I have created a 'Hello World' type test suite, but I can't seem to have it run any tests. When executed, it simply says:
reached run function
Process finished with exit code 0
I can thus tell that my two functions containing tests are never executed, as they contain print statements that are never printed.
This is the source code of my tests/run.ceylon file:
import ceylon.test {
TestRunner, createTestRunner
}
Anything myTests1 () {
// assert something true!
assert(40 + 2 == 42);
print("myTests1");
return null;
}
void myTests2 () {
// assert something false!
assert(2 + 2 == 54);
print("myTests2");
}
"Run the module `tests`."
shared void run() {
print("reached run function");
TestRunner myTestRunner = createTestRunner(
[`function myTests1`, `function myTests2`]);
myTestRunner.run();
}
the test function has to be annotated with test annotation, see https://modules.ceylon-lang.org/repo/1/ceylon/test/1.3.3.1/module-doc/api/index.html#start
I've writen a simple program based on a sample of the wdk that scans the memory from a dump file.
Now, I'd like to do the same on the process while it's running and I'm facing several issues:
I don't know how to break the running process
when leaving my program, the debugee is closed whereas I called DetachProcess.
Thanks
void ApplyCommandLineArguments(void)
{
HRESULT Status;
// Install output callbacks so we get any output that the
// later calls produce.
if ((Status = g_Client->SetOutputCallbacks(&g_OutputCb)) != S_OK)
{
Exit(1, "SetOutputCallbacks failed, 0x%X\n", Status);
}
if (isDump())
{
// Everything's set up so open the dump file.
if ((Status = g_Client->OpenDumpFile(g_DumpFile)) != S_OK)
{
Exit(1, "OpenDumpFile failed, 0x%X\n", Status);
}
// Finish initialization by waiting for the event that
// caused the dump. This will return immediately as the
// dump file is considered to be at its event.
if ((Status = g_Control->WaitForEvent(DEBUG_WAIT_DEFAULT,
INFINITE)) != S_OK)
{
Exit(1, "WaitForEvent failed, 0x%X\n", Status);
}
}
else
{
if ((Status = g_Client->AttachProcess(0,GetPid(),0/*DEBUG_ATTACH_NONINVASIVE*/)) != S_OK)
{
Exit(1, "AttachProcess failed, 0x%X\n", Status);
}
}
// Everything is now initialized and we can make any
// queries we want.
}