package Ġtasks Ċ Ċ import Ġcom . github . docker java . api . async . Result Callback Ċ import Ġcom . github . docker java . api . command . Create Container Cmd Ċ import Ġcom . github . docker java . api . command . Inspect Container Response Ċ import Ġcom . github . docker java . api . exception . NotFoundException Ċ import Ġcom . github . docker java . api . exception . Not Modified Exception Ċ import Ġcom . github . docker java . api . model . Frame Ċ import Ġorg . gradle . api . tasks .* Ċ import Ġorg . gradle . kotlin . dsl . property Ċ import Ġjava . time . Duration . of Minutes Ċ import Ġjava . time . Instant Ċ import Ġjava . time . format . DateTime Formatter Ċ import Ġkotlin . concurrent . thread Ċ Ċ @ Suppress (" Un stable Api Usage ", Ġ" Member Visibility Can Be Private ") Ċ @ Cache able Task Ċ abstract Ġclass ĠDocker Container Ġ: ĠDocker Client () Ġ{ ĊĊĠĠĠ Ġ// ĠNot Ġmarked Ġas Ġinput Ġas Ġthe Ġtag Ġcan Ġchange Ġbut Ġthe Ġimage Ġcontents Ġmay Ġbe Ġthe Ġsame Ġand Ġwe Ġdo Ġnot Ġneed Ġto Ġrer un . ĊĠĠĠ Ġ@ Internal ĊĠĠĠ Ġval Ġimage Id Ġ= Ġproject . objects . property < String >() ĊĊĠĠĠ Ġ// ĠNot Ġactually Ġthe Ġimage Ġdigest Ġbut Ġrather Ġan Ġapproximation Ġthat Ġignores Ġtimestamps , Ġetc . ĊĠĠĠ Ġ// ĠSo Ġwe Ġdo Ġnot Ġrun Ġtest Ġunless Ġthe Ġimage Ġhas Ġactually Ġchanged . ĊĠĠĠ Ġ@ Input File ĊĠĠĠ Ġ@ Optional ĊĠĠĠ Ġ@ Path Sensitive ( Path Sensitivity . REL ATIVE ) ĊĠĠĠ Ġval Ġdigest Ġ= Ġproject . objects . file Property () ĊĊĠĠĠ Ġ// ĠCapture Ġthe Ġlog Ġoutput Ġof Ġthe Ġcommand Ġfor Ġlater Ġinspection . ĊĠĠĠ Ġ@ OutputFile ĊĠĠĠ Ġval Ġlog Ġ= Ġproject . objects . file Property (). convention ( project . layout . build Directory . file ("${ name }. log ")) ĊĊĠĠĠ Ġ// ĠIdentifier Ġof Ġthe Ġcontainer Ġstarted Ġto Ġrun Ġthis Ġtask . ĊĠĠĠ Ġ@ Suppress (" AN NOT ATION _ TARGET S _ NON _ EXIST ENT _ ACCESS OR ") ĊĠĠĠ Ġ@ get : Internal ĊĠĠĠ Ġval Ġcontainer Id Ġ= Ġproject . objects . property < String >() ĊĊĠĠĠ Ġ@ Internal ĊĠĠĠ Ġval Ġinfo Ġ= Ġproject . objects . property < Inspect Container Response >() ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġ// ĠR er un Ġtest Ġif Ġany Ġof Ġthe Ġfiles Ġin Ġthe Ġdirectory Ġchanges , Ġas Ġlikely Ġthey Ġare ĊĠĠĠĠĠĠĠ Ġ// Ġbind Ġmounted Ġor Ġsecrets , Ġetc . ĠThe Ġcould Ġaffect Ġthe Ġoutcome Ġof Ġthe Ġtest . ĊĠĠĠĠĠĠĠ Ġinputs . dir ( project . project Dir ) ĊĊĠĠĠĠĠĠĠ Ġ// ĠBy Ġdefault Ġlimit Ġmax Ġexecution Ġtime Ġto Ġa Ġminute . ĊĠĠĠĠĠĠĠ Ġtimeout . convention ( of Minutes ( 5 )) ĊĊĠĠĠĠĠĠĠ Ġ// ĠIf Ġthere Ġis Ġa Ġparent Ġproject Ġwith Ġa Ġbuild Ġtask Ġassume Ġthat Ġdocker Ġimage Ġis Ġthe Ġone Ġwe Ġwant Ġto Ġuse Ġunless ĊĠĠĠĠĠĠĠ Ġ// Ġspecified Ġotherwise . ĊĠĠĠĠĠĠĠ Ġbuild Task ?. let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtask Ġ= Ġit . get () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġimage Id . convention ( task . options . tags . get (). first ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdigest . convention ( task . digest ) ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġ// ĠEnsure Ġwe Ġdo Ġnot Ġleave Ġcontainer Ġrunning Ġif Ġsomething Ġgoes Ġwrong . ĊĠĠĠĠĠĠĠ Ġproject . gradle . build Finished Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠMay Ġbe Ġcalled Ġbefore Ġcreation Ġof Ġcontainer Ġif Ġbuild Ġis Ġcancelled Ġetc . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( container Id . isPresent ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġremove ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠTo Ġbe Ġable Ġto Ġupdate Ġthe Ġlog Ġand Ġview Ġafter Ġcompletion Ġwe Ġneed Ġit Ġon Ġa Ġseparate Ġthread . ĊĠĠĠ Ġ@ get : Internal ĊĠĠĠ Ġval Ġlogging Thread Ġby Ġlazy Ġ{ ĊĠĠĠĠĠĠĠ Ġthread ( start Ġ= Ġfalse ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . get (). as File . buffered Writer (). use Ġ{ Ġwriter Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġdocker Client . log Container Cmd ( container Id . get ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Follow Stream ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Std Out ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Std Err ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. exec ( object Ġ: ĠResult Callback . Adapter < Frame >() Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Next ( frame : ĠFrame ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġtimestamp Ġ= ĠDateTime Formatter . ISO _ INST ANT . format ( Instant . now ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġpayload Ġ= ĠString ( frame . payload ). trim Ġ{ Ġit Ġ<= Ġ' Ġ' Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġline Ġ= Ġ" [$ timestamp ] Ġ${ frame . stream Type }: Ġ$ payload " ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlogger . info ( line ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġwriter . write ("$ line \ n ") ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ}). await Completion () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcreate () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! container Id . isPresent ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer Id . set ( docker Client . create Container Cmd ( image Id . get ()). exec (). id ) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcreate ( action : ĠCreate Container Cmd . () Ġ-> ĠCreate Container Cmd ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! container Id . isPresent ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdocker Client . create Container Cmd ( image Id . get ()). let Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġcontainer Id . set ( action ( it ). exec (). id ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġstart () Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdocker Client . start Container Cmd ( container Id . get ()). exec () ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠNot Modified Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠIgnore Ġif Ġcontainer Ġhas Ġalready Ġstarted . ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġlogging Thread . start () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġstop () Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdocker Client . stop Container Cmd ( container Id . get ()). exec () ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠNot Modified Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠIgnore Ġif Ġnot Ġmodified , Ġas Ġit Ġhas Ġalready Ġbeen Ġstopped . ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠUn recover able Ġerror , Ġuser Ġwill Ġhave Ġto Ġclean Ġup Ġtheir Ġenvironment . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġlogging Thread . join () Ġ// ĠContainer Ġhas Ġstopped Ġfinish Ġlogging . ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġwait () Ġ= ĊĠĠĠĠĠĠĠ Ġdocker Client . wait Container Cmd ( container Id . get ()). exec ( Result Callback . Adapter ()) ?. await Completion () ĊĊĠĠĠ Ġfun Ġinspect (): ĠIn spect Container Response Ġ= Ġdocker Client . inspect Container Cmd ( container Id . get ()). exec () ĊĊĠĠĠ Ġfun Ġremove ( force : ĠBoolean Ġ= Ġfalse ) Ġ{ ĊĠĠĠĠĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdocker Client ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. remove Container Cmd ( container Id . get ()) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Force ( force ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. exec () ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠNotFound Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠIgnore Ġif Ġnot Ġfound , Ġas Ġit Ġhas Ġalready Ġbeen Ġremoved . ĊĠĠĠĠĠĠĠ Ġ} Ġcatch Ġ( e : ĠException ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// ĠUn recover able Ġerror , Ġuser Ġwill Ġhave Ġto Ġclean Ġup Ġtheir Ġenvironment . ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow Ġe ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ// ĠExec utes Ġcallback Ġfor Ġeach Ġline Ġof Ġlog Ġoutput Ġuntil Ġthe Ġstream Ġends Ġor Ġthe Ġcallback Ġreturns Ġfalse . ĊĠĠĠ Ġfun Ġuntil Output ( callback : Ġ( String ) Ġ-> ĠBoolean ) Ġ{ ĊĠĠĠĠĠĠĠ Ġdocker Client . log Container Cmd ( container Id . get ()) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Tail All () ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Follow Stream ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Std Out ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. with Std Err ( true ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ. exec ( object Ġ: ĠResult Callback . Adapter < Frame >() Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġoverride Ġfun Ġon Next ( frame : ĠFrame ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġval Ġline Ġ= ĠString ( frame . payload ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ(! callback ( line )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġclose () ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsuper . onNext ( frame ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ}) ?. await Completion () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun ĠsetUp () Ġ{ ĊĠĠĠĠĠĠĠ Ġcreate () ĊĠĠĠĠĠĠĠ Ġstart () ĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun ĠsetUp ( action : ĠCreate Container Cmd . () Ġ-> ĠCreate Container Cmd ) Ġ{ ĊĠĠĠĠĠĠĠ Ġcreate ( action ) ĊĠĠĠĠĠĠĠ Ġstart () ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun ĠtearDown () Ġ{ ĊĠĠĠĠĠĠĠ Ġstop () ĊĠĠĠĠĠĠĠ Ġinfo . set ( inspect ()) ĊĠĠĠĠĠĠĠ Ġremove ( true ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġfun Ġcheck ExitCode ( expected : ĠLong ) Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġname Ġ= Ġinfo . get (). name ĊĠĠĠĠĠĠĠ Ġval Ġstate Ġ= Ġinfo . get (). state ĊĠĠĠĠĠĠĠ Ġif Ġ( state . exit Code Long Ġ!= Ġexpected ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠRuntimeException (" Container ĠImage : Ġ'${ image Id . get () }' ĠName : Ġ'$ name ' ĠID : Ġ'${ container Id . get () }' Ġexited Ġwith Ġ${ state . exit Code Long } Ġand Ġstatus Ġ${ state . status }. ") ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ