如何在sbt scripted插件中实现finally式的文件清理逻辑?
解决sbt scripted任务的动态文件清理问题
方案一:与scripted任务强绑定的清理(执行后必清理)
你之前的写法出现循环依赖,是因为重写scripted时引用了当前项目中正在定义的scripted任务。可以改为直接调用ScriptedPlugin提供的原始scripted任务,避免循环:
首先定义创建和清理任务:
lazy val createScriptedGlobalResolvers = taskKey[Unit]("生成scripted所需的临时文件") lazy val cleanupScriptedGlobalResolvers = taskKey[Unit]("清理scripted生成的临时文件") createScriptedGlobalResolvers := { // 替换为你的文件创建逻辑 val tempFile = baseDirectory.value / "scripted-temp-resolvers" IO.write(tempFile, "临时解析器配置内容") } cleanupScriptedGlobalResolvers := { // 替换为你的文件清理逻辑 val tempFile = baseDirectory.value / "scripted-temp-resolvers" if (tempFile.exists()) IO.delete(tempFile) }
然后重写scripted任务,确保执行前后的逻辑:
scripted := Def.inputTaskDyn { val args = sbt.complete.DefaultParsers.spaceDelimited("<arg>").parsed // 先执行文件创建 createScriptedGlobalResolvers.value // 动态生成任务,执行原始scripted并在finally中清理 Def.task { try { // 调用ScriptedPlugin的原始scripted任务,避免循环依赖 ScriptedPlugin.scripted.toTask(" " + args.mkString(" ")).value } finally { cleanupScriptedGlobalResolvers.value } } }.evaluated
方案二:sbt退出时自动清理(支持崩溃场景)
如果希望即使sbt意外崩溃也能清理临时文件,可以使用以下两种方式:
方式1:JVM关闭钩子(推荐,崩溃时也触发)
在创建文件的任务中添加钩子,JVM退出时自动执行清理:
createScriptedGlobalResolvers := { val tempFile = baseDirectory.value / "scripted-temp-resolvers" IO.write(tempFile, "临时解析器配置内容") sys.addShutdownHook { if (tempFile.exists()) IO.delete(tempFile) } }
方式2:sbt全局卸载钩子
通过sbt的onUnload钩子,在sbt退出时执行清理:
onUnload in Global := { val originalHook = (onUnload in Global).value (state: State) => { cleanupScriptedGlobalResolvers.value originalHook(state) } }
方案选择
- 若临时文件仅在
scripted执行时生成,优先选方案一,避免不必要的清理操作; - 若担心sbt崩溃导致文件残留,方案二的JVM钩子更可靠,确保任何情况下JVM退出都会清理。
内容的提问来源于stack exchange,提问作者Justin Pihony
相关产品推荐
相关产品推荐

