Repository: 7mind/izumi
Pull request #1147 (2020-07-15 23:25:06)

locator can be accessed outside of launcher


Patch:
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/ContainerResource.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/ContainerResource.scala
index ce617925c..3d2f53410 100644
--- a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/ContainerResource.scala
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/ContainerResource.scala
@@ -19,7 +19,6 @@ import izumi.fundamentals.platform.integration.ResourceCheck
 import izumi.fundamentals.platform.network.IzSockets
 import izumi.fundamentals.platform.strings.IzString._
 import izumi.logstage.api.IzLogger
-import izumi.fundamentals.platform.basics.IzBoolean._
 
 import scala.annotation.nowarn
 import scala.concurrent.duration._
diff --git a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/Docker.scala b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/Docker.scala
index 156379534..cbe2cbc35 100644
--- a/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/Docker.scala
+++ b/distage/distage-framework-docker/src/main/scala/izumi/distage/docker/Docker.scala
@@ -214,7 +214,7 @@ object Docker {
           GlobalDockerReusePolicy.ReuseDisabled
         case Some("ReuseButAlwaysKill") =>
           GlobalDockerReusePolicy.ReuseButAlwaysKill
-        case Some("ReuseButAlwaysKill") =>
+        case Some("ReuseEnabled") =>
           GlobalDockerReusePolicy.ReuseEnabled
         case other =>
           throw new IllegalArgumentException(s"Unexpected config value for reuse policy: $other")
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
index 521d0afb3..760a98b43 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppMain.scala
@@ -1,11 +1,12 @@
 package izumi.distage.roles
 
-import izumi.distage.roles.services.AppFailureHandler
+import izumi.distage.roles.launcher.RoleAppLauncher
+import izumi.distage.roles.launcher.services.AppFailureHandler
 import izumi.fundamentals.platform.cli.model.raw.{RawAppArgs, RawRoleParams}
 import izumi.fundamentals.platform.cli.{CLIParser, ParserFailureHandler}
 
-abstract class RoleAppMain(
-  launcher: RoleAppLauncher,
+abstract class RoleAppMain[F[_]](
+  launcher: RoleAppLauncher[F],
   failureHandler: AppFailureHandler,
   parserFailureHandler: ParserFailureHandler,
 ) {
@@ -22,7 +23,10 @@ abstract class RoleAppMain(
           val requestedRoles = parameters.roles
           val requestedRoleSet = requestedRoles.map(_.role).toSet
           val knownRequiredRoles = requiredRoles.filterNot(requestedRoleSet contains _.role)
-          launcher.launch(parameters.copy(roles = rolesToLaunch(requestedRoles, knownRequiredRoles)))
+          launcher.launch(parameters.copy(roles = rolesToLaunch(requestedRoles, knownRequiredRoles))).use {
+            app =>
+              app.run()
+          }
       }
     } catch {
       case t: Throwable =>
@@ -37,22 +41,22 @@ abstract class RoleAppMain(
 
 object RoleAppMain {
 
-  class Default(launcher: RoleAppLauncher)
+  class Default[F[_]](launcher: RoleAppLauncher[F])
     extends RoleAppMain(
       launcher,
       AppFailureHandler.TerminatingHandler,
       ParserFailureHandler.TerminatingHandler,
     )
 
-  class Safe(launcher: RoleAppLauncher)
-    extends RoleAppMain(
+  class Safe[F[_]](launcher: RoleAppLauncher[F])
+    extends RoleAppMain[F](
       launcher,
       AppFailureHandler.PrintingHandler,
       ParserFailureHandler.PrintingHandler,
     )
 
-  class Silent(launcher: RoleAppLauncher)
-    extends RoleAppMain(
+  class Silent[F[_]](launcher: RoleAppLauncher[F])
+    extends RoleAppMain[F](
       launcher,
       AppFailureHandler.NullHandler,
       ParserFailureHandler.NullHandler,
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/Help.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/Help.scala
index c0562cbef..4828e359f 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/Help.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/bundled/Help.scala
@@ -2,7 +2,7 @@ package izumi.distage.roles.bundled
 
 import izumi.distage.framework.model.ActivationInfo
 import izumi.distage.model.effect.DIEffect
-import izumi.distage.roles.RoleAppLauncher.Options
+import izumi.distage.roles.bundled.ConfigWriter.Options
 import izumi.distage.roles.model.meta.RolesInfo
 import izumi.distage.roles.model.{RoleDescriptor, RoleTask}
 import izumi.fundamentals.platform.cli.model.raw.RawEntrypointParams
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncher.scala
similarity index 79%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncher.scala
index 64ec5e0ea..1b03f6dba 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncher.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncher.scala
@@ -1,8 +1,10 @@
-package izumi.distage.roles
+package izumi.distage.roles.launcher
 
 import cats.effect.LiftIO
-import distage.{TagK, TagKK}
+import distage.{DIResourceBase, TagK, TagKK}
+import izumi.distage.roles.AppShutdownStrategy
 import izumi.distage.roles.AppShutdownStrategy.{BIOShutdownStrategy, CatsEffectIOShutdownStrategy, JvmExitHookLatchShutdownStrategy}
+import izumi.distage.roles.launcher.services.StartupPlanExecutor.PreparedApp
 import izumi.functional.bio.BIOAsync
 import izumi.fundamentals.platform.cli.model.raw.RawAppArgs
 import izumi.fundamentals.platform.cli.model.schema.ParserDef
@@ -10,8 +12,8 @@ import izumi.fundamentals.platform.functional.Identity
 
 import scala.concurrent.ExecutionContext
 
-trait RoleAppLauncher {
-  def launch(parameters: RawAppArgs): Unit
+trait RoleAppLauncher[F[_]] {
+  def launch(parameters: RawAppArgs): DIResourceBase[Identity, PreparedApp[F]]
 }
 
 object RoleAppLauncher {
@@ -28,8 +30,8 @@ object RoleAppLauncher {
     override protected val shutdownStrategy: AppShutdownStrategy[F] = new CatsEffectIOShutdownStrategy(executionContext)
   }
 
-  abstract class LauncherBIO[F[+_, +_]: TagKK: BIOAsync] extends RoleAppLauncherImpl[F[Throwable, ?]] {
-    override protected val shutdownStrategy: AppShutdownStrategy[F[Throwable, ?]] = new BIOShutdownStrategy[F]
+  abstract class LauncherBIO[F[+_, +_]: TagKK: BIOAsync] extends RoleAppLauncherImpl[F[Throwable, *]] {
+    override protected val shutdownStrategy: AppShutdownStrategy[F[Throwable, *]] = new BIOShutdownStrategy[F]
   }
 
   abstract class LauncherIdentity extends RoleAppLauncherImpl[Identity] {
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncherImpl.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncherImpl.scala
similarity index 95%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncherImpl.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncherImpl.scala
index 69e0c9b8f..7aa4d7320 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/RoleAppLauncherImpl.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/RoleAppLauncherImpl.scala
@@ -1,4 +1,4 @@
-package izumi.distage.roles
+package izumi.distage.roles.launcher
 
 import java.io.File
 
@@ -7,20 +7,21 @@ import izumi.distage.config.codec.DIConfigReader
 import izumi.distage.config.model.AppConfig
 import izumi.distage.framework.config.PlanningOptions
 import izumi.distage.framework.model.ActivationInfo
-import izumi.distage.framework.services.ResourceRewriter.RewriteRules
 import izumi.distage.framework.services._
 import izumi.distage.model.definition.Activation
 import izumi.distage.model.recursive.Bootloader
 import izumi.distage.plugins.load.{PluginLoader, PluginLoaderDefaultImpl}
 import izumi.distage.plugins.merge.{PluginMergeStrategy, SimplePluginMergeStrategy}
 import izumi.distage.plugins.{PluginBase, PluginConfig}
-import izumi.distage.roles.RoleAppLauncher.Options
-import izumi.distage.roles.RoleAppLauncherImpl.ActivationConfig
+import izumi.distage.roles.AppShutdownStrategy
+import izumi.distage.roles.launcher.RoleAppLauncher.Options
+import izumi.distage.roles.launcher.RoleAppLauncherImpl.ActivationConfig
 import izumi.distage.roles.model.exceptions.DIAppBootstrapException
 import izumi.distage.roles.model.meta.{LibraryReference, RolesInfo}
-import izumi.distage.roles.services.StartupPlanExecutor.Filters
-import izumi.distage.roles.services.{RoleAppActivationParser, _}
+import izumi.distage.roles.launcher.services.StartupPlanExecutor.{Filters, PreparedApp}
+import izumi.distage.roles.launcher.services.{RoleAppActivationParser, _}
 import izumi.fundamentals.platform.cli.model.raw.RawAppArgs
+import izumi.fundamentals.platform.functional.Identity
 import izumi.fundamentals.platform.language.unused
 import izumi.fundamentals.platform.resources.IzManifest
 import izumi.fundamentals.platform.strings.IzString._
@@ -49,7 +50,7 @@ import scala.reflect.ClassTag
   * 16. Shutdown executors
   */
 // FIXME: rewrite using DI https://github.com/7mind/izumi/issues/779
-abstract class RoleAppLauncherImpl[F[_]: TagK] extends RoleAppLauncher {
+abstract class RoleAppLauncherImpl[F[_]: TagK] extends RoleAppLauncher[F] {
   protected def pluginConfig: PluginConfig
   protected def bootstrapPluginConfig: PluginConfig = PluginConfig.empty
   protected def shutdownStrategy: AppShutdownStrategy[F]
@@ -68,7 +69,7 @@ abstract class RoleAppLauncherImpl[F[_]: TagK] extends RoleAppLauncher {
   protected def configActivationSection: String = "activation"
   protected def defaultBaseConfigs: Seq[String] = ConfigLoader.defaultBaseConfigs
 
-  def launch(parameters: RawAppArgs): Unit = {
+  def launch(parameters: RawAppArgs): DIResourceBase[Identity, PreparedApp[F]] = {
     val earlyLogger = EarlyLoggers.makeEarlyLogger(parameters, defaultLogLevel)
     showBanner(earlyLogger, additionalLibraryReferences)
 
@@ -173,9 +174,7 @@ abstract class RoleAppLauncherImpl[F[_]: TagK] extends RoleAppLauncher {
 
   protected def planningOptions(parameters: RawAppArgs): PlanningOptions = {
     PlanningOptions(
-      addGraphVizDump = parameters.globalParameters.hasFlag(Options.dumpContext),
-      warnOnCircularDeps = true,
-      rewriteRules = RewriteRules(),
+      addGraphVizDump = parameters.globalParameters.hasFlag(Options.dumpContext)
     )
   }
 
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/AppFailureHandler.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/AppFailureHandler.scala
similarity index 92%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/services/AppFailureHandler.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/AppFailureHandler.scala
index a7755ca20..52c658a8c 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/AppFailureHandler.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/AppFailureHandler.scala
@@ -1,4 +1,4 @@
-package izumi.distage.roles.services
+package izumi.distage.roles.launcher.services
 
 trait AppFailureHandler {
   def onError(t: Throwable): Unit
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/EarlyLoggers.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/EarlyLoggers.scala
similarity index 90%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/services/EarlyLoggers.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/EarlyLoggers.scala
index ba1fecaef..2d4222e38 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/EarlyLoggers.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/EarlyLoggers.scala
@@ -1,8 +1,7 @@
-package izumi.distage.roles.services
+package izumi.distage.roles.launcher.services
 
 import izumi.distage.config.model.AppConfig
-import izumi.distage.roles.RoleAppLauncher.Options
-import izumi.distage.roles.logger.SimpleLoggerConfigurator
+import izumi.distage.roles.launcher.RoleAppLauncher.Options
 import izumi.fundamentals.platform.cli.model.raw.{RawAppArgs, RawEntrypointParams}
 import izumi.logstage.api.Log.Level
 import izumi.logstage.api.{IzLogger, Log}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppActivationParser.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppActivationParser.scala
similarity index 98%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppActivationParser.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppActivationParser.scala
index 4a321a096..abe098e47 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppActivationParser.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppActivationParser.scala
@@ -1,4 +1,4 @@
-package izumi.distage.roles.services
+package izumi.distage.roles.launcher.services
 
 import izumi.distage.framework.model.ActivationInfo
 import izumi.distage.model.definition.{Activation, Axis}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppExecutor.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppExecutor.scala
similarity index 87%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppExecutor.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppExecutor.scala
index 51354d3b7..229a00c79 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleAppExecutor.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleAppExecutor.scala
@@ -1,20 +1,23 @@
-package izumi.distage.roles.services
+package izumi.distage.roles.launcher.services
 
 import distage.TagK
 import izumi.distage.framework.services.RoleAppPlanner.AppStartupPlans
 import izumi.distage.model.Locator
+import izumi.distage.model.definition.DIResource
+import izumi.distage.model.definition.DIResource.DIResourceBase
 import izumi.distage.model.effect.DIEffect
 import izumi.distage.model.effect.DIEffect.syntax._
 import izumi.distage.roles._
 import izumi.distage.roles.model.meta.RolesInfo
 import izumi.distage.roles.model.exceptions.DIAppBootstrapException
 import izumi.distage.roles.model.{AbstractRole, RoleService, RoleTask}
-import izumi.distage.roles.services.StartupPlanExecutor.Filters
+import izumi.distage.roles.launcher.services.StartupPlanExecutor.{Filters, PreparedApp}
 import izumi.fundamentals.platform.cli.model.raw.RawAppArgs
+import izumi.fundamentals.platform.functional.Identity
 import izumi.logstage.api.IzLogger
 
 trait RoleAppExecutor[F[_]] {
-  def runPlan(appPlan: AppStartupPlans): Unit
+  def runPlan(appPlan: AppStartupPlans): DIResourceBase[Identity, PreparedApp[F]]
 }
 
 object RoleAppExecutor {
@@ -28,12 +31,13 @@ object RoleAppExecutor {
     filters: Filters[F],
   ) extends RoleAppExecutor[F] {
 
-    final def runPlan(appPlan: AppStartupPlans): Unit = {
-      try {
-        startupPlanExecutor.execute(appPlan, filters)(doRun)
-      } finally {
-        hook.release()
-      }
+    final def runPlan(appPlan: AppStartupPlans): DIResourceBase[Identity, PreparedApp[F]] = {
+      DIResource
+        .makeSimple(())(_ => hook.release())
+        .flatMap {
+          _ =>
+            startupPlanExecutor.execute(appPlan, filters)(doRun)
+        }
     }
 
     protected def doRun(locator: Locator, effect: DIEffect[F]): F[Unit] = {
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleProvider.scala
similarity index 98%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleProvider.scala
index 28ebfd1d7..547c349fb 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/RoleProvider.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/RoleProvider.scala
@@ -1,4 +1,4 @@
-package izumi.distage.roles.services
+package izumi.distage.roles.launcher.services
 
 import distage._
 import izumi.distage.model.definition.Binding
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/SimpleLoggerConfigurator.scala
similarity index 95%
rename from distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala
rename to distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/SimpleLoggerConfigurator.scala
index 90534b52a..d1c67ccae 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/logger/SimpleLoggerConfigurator.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/SimpleLoggerConfigurator.scala
@@ -1,8 +1,8 @@
-package izumi.distage.roles.logger
+package izumi.distage.roles.launcher.services
 
 import com.typesafe.config.Config
 import izumi.distage.config.codec.DIConfigReader
-import izumi.distage.roles.logger.SimpleLoggerConfigurator.SinksConfig
+import izumi.distage.roles.launcher.services.SimpleLoggerConfigurator.SinksConfig
 import izumi.logstage.api.Log.Level.Warn
 import izumi.logstage.api.Log.Message
 import izumi.logstage.api.config.{LoggerConfig, LoggerPathConfig}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/StartupPlanExecutor.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/StartupPlanExecutor.scala
new file mode 100644
index 000000000..ab01ffebc
--- /dev/null
+++ b/distage/distage-framework/src/main/scala/izumi/distage/roles/launcher/services/StartupPlanExecutor.scala
@@ -0,0 +1,95 @@
+package izumi.distage.roles.launcher.services
+
+import distage.{Injector, TagK}
+import izumi.distage.framework.services.IntegrationChecker
+import izumi.distage.framework.services.RoleAppPlanner.AppStartupPlans
+import izumi.distage.model.Locator
+import izumi.distage.model.definition.DIResource
+import izumi.distage.model.effect.{DIEffect, DIEffectRunner}
+import izumi.distage.model.provisioning.PlanInterpreter.FinalizerFilter
+import izumi.distage.roles.launcher.services.StartupPlanExecutor.PreparedApp
+import izumi.fundamentals.platform.functional.Identity
+
+trait StartupPlanExecutor[F[_]] {
+  def execute(
+    appPlan: AppStartupPlans,
+    filters: StartupPlanExecutor.Filters[F],
+  )(doRun: (Locator, DIEffect[F]) => F[Unit]
+  ): DIResource.DIResourceBase[Identity, PreparedApp[F]]
+}
+
+object StartupPlanExecutor {
+  case class PreparedApp[F[_]](
+    app: DIResource.DIResourceBase[F, Locator],
+    runner: DIEffectRunner[F],
+    effect: DIEffect[F],
+  ) {
+    def run(): Unit = {
+      runner.run(app.use(_ => effect.unit)(effect))
+    }
+  }
+
+  def apply[F[_]: TagK](injector: Injector, checker: IntegrationChecker[F]): StartupPlanExecutor[F] = {
+    new StartupPlanExecutor.Impl[F](injector, checker)
+  }
+
+  final case class Filters[F[_]](
+    filterF: FinalizerFilter[F],
+    filterId: FinalizerFilter[Identity],
+  )
+  object Filters {
+    def all[F[_]]: Filters[F] = Filters[F](FinalizerFilter.all, FinalizerFilter.all)
+  }
+
+  class Impl[F[_]: TagK](
+    injector: Injector,
+    integrationChecker: IntegrationChecker[F],
+  ) extends StartupPlanExecutor[F] {
+    def execute(
+      appPlan: AppStartupPlans,
+      filters: StartupPlanExecutor.Filters[F],
+    )(doRun: (Locator, DIEffect[F]) => F[Unit]
+    ): DIResource.DIResourceBase[Identity, PreparedApp[F]] = {
+      injector
+        .produceFX[Identity](appPlan.runtime, filters.filterId)
+        .map {
+          runtimeLocator =>
+            val runner = runtimeLocator.get[DIEffectRunner[F]]
+            implicit val effect: DIEffect[F] = runtimeLocator.get[DIEffect[F]]
+
+            PreparedApp(prepareMainResource(appPlan, filters, doRun, runtimeLocator)(effect), runner, effect)
+        }
+    }
+
+    private def prepareMainResource(
+      appPlan: AppStartupPlans,
+      filters: Filters[F],
+      doRun: (Locator, DIEffect[F]) => F[Unit],
+      runtimeLocator: Locator,
+    )(implicit
+      effect: DIEffect[F]
+    ): DIResource.DIResourceBase[F, Locator] = {
+      Injector
+        .inherit(runtimeLocator)
+        .produceFX[F](appPlan.app.shared, filters.filterF)
+        .flatMap {
+          sharedLocator =>
+            Injector
+              .inherit(sharedLocator)
+              .produceFX[F](appPlan.app.side, filters.filterF)
+              .evalTap {
+                integrationLocator =>
+                  integrationChecker.checkOrFail(appPlan.app.side.declaredRoots, integrationLocator)
+              }
+              .flatMap {
+                _ => // we don't need integration locator
+                  Injector
+                    .inherit(sharedLocator)
+                    .produceFX[F](appPlan.app.primary, filters.filterF)
+                    .evalTap(doRun(_, effect))
+              }
+        }
+    }
+  }
+
+}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala b/distage/distage-framework/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala
deleted file mode 100644
index 1433c2c91..000000000
--- a/distage/distage-framework/src/main/scala/izumi/distage/roles/services/StartupPlanExecutor.scala
+++ /dev/null
@@ -1,68 +0,0 @@
-package izumi.distage.roles.services
-
-import distage.{Injector, TagK}
-import izumi.distage.framework.services.IntegrationChecker
-import izumi.distage.framework.services.RoleAppPlanner.AppStartupPlans
-import izumi.distage.model.Locator
-import izumi.distage.model.effect.DIEffect.syntax._
-import izumi.distage.model.effect.{DIEffect, DIEffectRunner}
-import izumi.distage.model.provisioning.PlanInterpreter.FinalizerFilter
-import izumi.fundamentals.platform.functional.Identity
-
-trait StartupPlanExecutor[F[_]] {
-  def execute(appPlan: AppStartupPlans, filters: StartupPlanExecutor.Filters[F])(doRun: (Locator, DIEffect[F]) => F[Unit]): Unit
-}
-
-object StartupPlanExecutor {
-  def apply[F[_]: TagK](injector: Injector, checker: IntegrationChecker[F]): StartupPlanExecutor[F] = {
-    new StartupPlanExecutor.Impl[F](injector, checker)
-  }
-
-  final case class Filters[F[_]](
-    filterF: FinalizerFilter[F],
-    filterId: FinalizerFilter[Identity],
-  )
-  object Filters {
-    def all[F[_]]: Filters[F] = Filters[F](FinalizerFilter.all, FinalizerFilter.all)
-  }
-
-  class Impl[F[_]: TagK](
-    injector: Injector,
-    integrationChecker: IntegrationChecker[F],
-  ) extends StartupPlanExecutor[F] {
-    def execute(appPlan: AppStartupPlans, filters: StartupPlanExecutor.Filters[F])(doRun: (Locator, DIEffect[F]) => F[Unit]): Unit = {
-      injector
-        .produceFX[Identity](appPlan.runtime, filters.filterId)
-        .use {
-          runtimeLocator =>
-            val runner = runtimeLocator.get[DIEffectRunner[F]]
-            implicit val effect: DIEffect[F] = runtimeLocator.get[DIEffect[F]]
-
-            runner.run {
-              Injector
-                .inherit(runtimeLocator)
-                .produceFX[F](appPlan.app.shared, filters.filterF)
-                .use {
-                  sharedLocator =>
-                    Injector
-                      .inherit(sharedLocator)
-                      .produceFX[F](appPlan.app.side, filters.filterF)
-                      .use {
-                        integrationLocator =>
-                          integrationChecker.checkOrFail(appPlan.app.side.declaredRoots, integrationLocator)
-                      }
-                      .flatMap {
-                        _ =>
-                          Injector
-                            .inherit(sharedLocator)
-                            .produceFX[F](appPlan.app.primary, filters.filterF)
-                            .use(doRun(_, effect))
-                      }
-                }
-            }
-        }
-    }
-
-  }
-
-}
diff --git a/distage/distage-framework/src/main/scala/izumi/distage/staticinjector/plugins/macros/StaticPluginCheckerMacro.scala b/distage/distage-framework/src/main/scala/izumi/distage/staticinjector/plugins/macros/StaticPluginCheckerMacro.scala
index 186f7b80a..bd42d871a 100644
--- a/distage/distage-framework/src/main/scala/izumi/distage/staticinjector/plugins/macros/StaticPluginCheckerMacro.scala
+++ b/distage/distage-framework/src/main/scala/izumi/distage/staticinjector/plugins/macros/StaticPluginCheckerMacro.scala
@@ -11,7 +11,7 @@ import izumi.distage.model.PlannerInput
 import izumi.distage.plugins.load.PluginLoaderDefaultImpl
 import izumi.distage.plugins.merge.SimplePluginMergeStrategy
 import izumi.distage.plugins.{PluginBase, PluginConfig}
-import izumi.distage.roles.services.RoleAppActivationParser
+import izumi.distage.roles.launcher.services.RoleAppActivationParser
 import izumi.distage.staticinjector.plugins.ModuleRequirements
 import izumi.fundamentals.platform.strings.IzString._
 import izumi.fundamentals.reflection.ReflectionUtil
diff --git a/fundamentals/fundamentals-platform/src/main/scala/izumi/fundamentals/platform/properties/DebugProperties.scala b/fundamentals/fundamentals-platform/src/main/scala/izumi/fundamentals/platform/properties/DebugProperties.scala
index e1d3b7458..09abe76df 100644
--- a/fundamentals/fundamentals-platform/src/main/scala/izumi/fundamentals/platform/properties/DebugProperties.scala
+++ b/fundamentals/fundamentals-platform/src/main/scala/izumi/fundamentals/platform/properties/DebugProperties.scala
@@ -2,8 +2,6 @@ package izumi.fundamentals.platform.properties
 
 import izumi.fundamentals.platform.strings.IzString._
 
-import scala.language.implicitConversions
-
 /**
   * Marker trait for objects that hold names of Java Properties
   * that control debug output for macros and internals of `izumi` libraries.


Test patch:
diff --git a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/TestLauncher.scala b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/TestLauncher.scala
index 1bd4170cf..82f52f93c 100644
--- a/distage/distage-framework/src/test/scala/izumi/distage/roles/test/TestLauncher.scala
+++ b/distage/distage-framework/src/test/scala/izumi/distage/roles/test/TestLauncher.scala
@@ -4,6 +4,7 @@ import cats.effect.IO
 import izumi.distage.plugins.PluginConfig
 import izumi.distage.roles.AppShutdownStrategy.ImmediateExitShutdownStrategy
 import izumi.distage.roles._
+import izumi.distage.roles.launcher.RoleAppLauncher
 import izumi.fundamentals.platform.language.SourcePackageMaterializer.thisPkg
 
 class TestLauncher extends RoleAppLauncher.LauncherF[IO] {
diff --git a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
index edb3445ce..39772fd7a 100644
--- a/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
+++ b/distage/distage-testkit-core/src/main/scala/izumi/distage/testkit/services/dstest/DistageTestRunner.scala
@@ -14,7 +14,7 @@ import izumi.distage.model.effect.DIEffect.syntax._
 import izumi.distage.model.effect.{DIEffect, DIEffectAsync, DIEffectRunner}
 import izumi.distage.model.exceptions.ProvisioningException
 import izumi.distage.model.plan.{ExecutableOp, TriSplittedPlan}
-import izumi.distage.roles.services.EarlyLoggers
+import izumi.distage.roles.launcher.services.EarlyLoggers
 import izumi.distage.testkit.DebugProperties
 import izumi.distage.testkit.TestConfig.ParallelLevel
 import izumi.distage.testkit.services.dstest.DistageTestRunner._