Skip to content

Commit

Permalink
Improve shell runner, use services & other
Browse files Browse the repository at this point in the history
  • Loading branch information
WarningImHack3r committed Jun 20, 2024
1 parent cc28f83 commit 8b1d27c
Show file tree
Hide file tree
Showing 12 changed files with 50 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ object SourceScanner {
val log = logger<SourceScanner>()

fun findShadcnImplementation(project: Project): Source<*>? {
val fileManager = FileManager(project)
val fileManager = FileManager.getInstance(project)
return fileManager.getFileContentsAtPath("components.json")?.let { componentsJson ->
val contents = Json.parseToJsonElement(componentsJson).jsonObject
val schema = contents["\$schema"]?.jsonPrimitive?.content ?: ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ package com.github.warningimhack3r.intellijshadcnplugin.backend.helpers

import com.github.warningimhack3r.intellijshadcnplugin.notifications.NotificationManager
import com.intellij.notification.NotificationType
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject

@Service(Service.Level.PROJECT)
class DependencyManager(private val project: Project) {
companion object {
private val log = logger<DependencyManager>()

@JvmStatic
fun getInstance(project: Project): DependencyManager = project.service()
}

enum class InstallationType {
DEV,
PROD
}

private fun getPackageManager(): String? {
val fileManager = FileManager(project)
val fileManager = FileManager.getInstance(project)
return mapOf(
"package-lock.json" to "npm",
"pnpm-lock.yaml" to "pnpm",
Expand All @@ -35,7 +45,7 @@ class DependencyManager(private val project: Project) {
*dependencyNames.toTypedArray()
).toTypedArray()
// check if the installation was successful
if (ShellRunner(project).execute(command) == null) {
if (ShellRunner.getInstance(project).execute(command) == null) {
NotificationManager(project).sendNotification(
"Failed to install dependencies",
"Failed to install dependencies: ${dependencyNames.joinToString { ", " }} (${command.joinToString(" ")}). Please install it manually.",
Expand All @@ -54,7 +64,7 @@ class DependencyManager(private val project: Project) {
*dependencyNames.toTypedArray()
).toTypedArray()
// check if the uninstallation was successful
if (ShellRunner(project).execute(command) == null) {
if (ShellRunner.getInstance(project).execute(command) == null) {
NotificationManager(project).sendNotification(
"Failed to uninstall dependencies",
"Failed to uninstall dependencies (${command.joinToString(" ")}). Please uninstall them manually.",
Expand All @@ -66,14 +76,14 @@ class DependencyManager(private val project: Project) {

fun getInstalledDependencies(): List<String> {
// Read the package.json file
return FileManager(project).getFileContentsAtPath("package.json")?.let { packageJson ->
return FileManager.getInstance(project).getFileContentsAtPath("package.json")?.let { packageJson ->
Json.parseToJsonElement(packageJson).jsonObject.filter {
it.key == "dependencies" || it.key == "devDependencies"
}.map { it.value.jsonObject.keys }.flatten().also {
logger<DependencyManager>().debug("Installed dependencies: $it")
log.debug("Installed dependencies: $it")
}
} ?: emptyList<String>().also {
logger<DependencyManager>().error("package.json not found")
log.error("package.json not found")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package com.github.warningimhack3r.intellijshadcnplugin.backend.helpers

import com.intellij.openapi.application.runReadAction
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
Expand All @@ -11,9 +13,13 @@ import com.intellij.psi.search.GlobalSearchScope
import java.io.IOException
import java.nio.file.NoSuchFileException

@Service(Service.Level.PROJECT)
class FileManager(private val project: Project) {
companion object {
private val log = logger<FileManager>()

@JvmStatic
fun getInstance(project: Project): FileManager = project.service()
}

fun saveFileAtPath(file: PsiFile, path: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import com.intellij.psi.PsiFile
import com.intellij.psi.PsiFileFactory

object PsiHelper {

fun createPsiFile(project: Project, fileName: String, text: String): PsiFile {
assert(fileName.contains('.')) { "File name must contain an extension" }
return runReadAction {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package com.github.warningimhack3r.intellijshadcnplugin.backend.helpers

import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.project.Project
import java.io.File

class ShellRunner(private val project: Project? = null) {
@Service(Service.Level.PROJECT)
class ShellRunner(private val project: Project) {
companion object {
private val log = logger<ShellRunner>()

@JvmStatic
fun getInstance(project: Project): ShellRunner = project.service()
}

private val failedWindowsPrograms = mutableSetOf<String>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
protected open fun getLocalConfig(): C {
return config?.also {
log.debug("Returning cached config")
} ?: FileManager(project).getFileContentsAtPath(configFile)?.let {
} ?: FileManager.getInstance(project).getFileContentsAtPath(configFile)?.let {
log.debug("Parsing config from $configFile")
try {
Json.decodeFromString(serializer, it).also {
Expand Down Expand Up @@ -163,7 +163,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
}

fun getInstalledComponents(): List<String> {
return FileManager(project).getFileAtPath(
return FileManager.getInstance(project).getFileAtPath(
"${resolveAlias(getLocalPathForComponents())}/ui"
)?.children?.map { file ->
if (file.isDirectory) file.name else file.name.substringBeforeLast(".")
Expand All @@ -179,7 +179,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
// Install component
val component = fetchComponent(componentName)
val installedComponents = getInstalledComponents()
val fileManager = FileManager(project)
val fileManager = FileManager.getInstance(project)
val notifManager = NotificationManager(project)
log.debug("Installing ${component.name} (installed: ${installedComponents.joinToString(", ")})")
setOf(component, *getRegistryDependencies(component).filter {
Expand Down Expand Up @@ -241,7 +241,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
}

// Install dependencies
val depsManager = DependencyManager(project)
val depsManager = DependencyManager.getInstance(project)
val depsToInstall = component.dependencies.filter { dependency ->
!depsManager.isDependencyInstalled(dependency)
}
Expand Down Expand Up @@ -283,7 +283,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
"/${remoteComponent.name}"
} else ""
}"
val fileManager = FileManager(project)
val fileManager = FileManager.getInstance(project)
return remoteComponent.files.all { file ->
val psiFile = PsiHelper.createPsiFile(
project, adaptFileExtensionToConfig(file.name), file.content
Expand All @@ -302,10 +302,10 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
val componentsDir =
"${resolveAlias(getLocalPathForComponents())}/${remoteComponent.type.substringAfterLast(":")}"
if (usesDirectoriesForComponents()) {
FileManager(project).deleteFileAtPath("$componentsDir/${remoteComponent.name}")
FileManager.getInstance(project).deleteFileAtPath("$componentsDir/${remoteComponent.name}")
} else {
remoteComponent.files.forEach { file ->
FileManager(project).deleteFileAtPath("$componentsDir/${file.name}")
FileManager.getInstance(project).deleteFileAtPath("$componentsDir/${file.name}")
}
}
// Remove dependencies no longer needed by any component
Expand All @@ -314,9 +314,10 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
val currentlyNeededDependencies = getInstalledComponents().map { component ->
remoteComponents.find { it.name == component }?.dependencies ?: emptyList()
}.flatten().toSet()
val uselessDependencies = DependencyManager(project).getInstalledDependencies().filter { dependency ->
dependency in allPossiblyNeededDependencies && dependency !in currentlyNeededDependencies
}
val uselessDependencies =
DependencyManager.getInstance(project).getInstalledDependencies().filter { dependency ->
dependency in allPossiblyNeededDependencies && dependency !in currentlyNeededDependencies
}
if (uselessDependencies.isNotEmpty()) {
val multipleDependencies = uselessDependencies.size > 1
val notifManager = NotificationManager(project)
Expand All @@ -331,7 +332,7 @@ abstract class Source<C : Config>(val project: Project, private val serializer:
listOf(
NotificationAction.createSimple("Remove") {
runAsync {
DependencyManager(project).uninstallDependencies(uselessDependencies)
DependencyManager.getInstance(project).uninstallDependencies(uselessDependencies)
}.then {
notifManager.sendNotificationAndHide(
"Removed dependenc${if (multipleDependencies) "ies" else "y"}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ open class ReactSource(project: Project) : Source<ReactConfig>(project, ReactCon
return alias
}
val configFile = if (getLocalConfig().tsx) "tsconfig.json" else "jsconfig.json"
val tsConfig = FileManager(project).getFileContentsAtPath(configFile)
val tsConfig = FileManager.getInstance(project).getFileContentsAtPath(configFile)
?: throw NoSuchFileException("$configFile not found")
val aliasPath = parseTsConfig(tsConfig)
.jsonObject["compilerOptions"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ open class SolidSource(project: Project) : Source<SolidConfig>(project, SolidCon
return alias
}
val configFile = "tsconfig.json"
val tsConfig = FileManager(project).getFileContentsAtPath(configFile)
val tsConfig = FileManager.getInstance(project).getFileContentsAtPath(configFile)
?: throw NoSuchFileException("$configFile not found")
val aliasPath = parseTsConfig(tsConfig)
.jsonObject["compilerOptions"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ open class SolidUISource(project: Project) : Source<SolidUIConfig>(project, Soli
return alias
}
val configFile = if (getLocalConfig().tsx) "tsconfig.json" else "jsconfig.json"
val tsConfig = FileManager(project).getFileContentsAtPath(configFile)
val tsConfig = FileManager.getInstance(project).getFileContentsAtPath(configFile)
?: throw NoSuchFileException("$configFile not found")
val aliasPath = parseTsConfig(tsConfig)
.jsonObject["compilerOptions"]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ open class SvelteSource(project: Project) : Source<SvelteConfig>(project, Svelte
log.warn("Alias $alias does not start with $, @ or ~, returning it as-is")
return alias
}
val usesKit = DependencyManager(project).isDependencyInstalled("@sveltejs/kit")
val usesKit = DependencyManager.getInstance(project).isDependencyInstalled("@sveltejs/kit")
val tsConfigName = if (getLocalConfig().typescript) "tsconfig.json" else "jsconfig.json"
val configFile = if (usesKit) ".svelte-kit/$tsConfigName" else tsConfigName
val fileManager = FileManager(project)
val fileManager = FileManager.getInstance(project)
var tsConfig = fileManager.getFileContentsAtPath(configFile)
if (tsConfig == null) {
if (!usesKit) throw NoSuchFileException("Cannot get $configFile")
val res = ShellRunner(project).execute(arrayOf("npx", "svelte-kit", "sync"))
val res = ShellRunner.getInstance(project).execute(arrayOf("npx", "svelte-kit", "sync"))
if (res == null) {
NotificationManager(project).sendNotification(
"Failed to generate $configFile",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ open class VueSource(project: Project) : Source<VueConfig>(project, VueConfig.se
else -> "tsconfig.json"
}.let { if (!config.typescript) "jsconfig.json" else it }

val tsConfig = FileManager(project).getFileContentsAtPath(tsConfigLocation)
val tsConfig = FileManager.getInstance(project).getFileContentsAtPath(tsConfigLocation)
?: throw NoSuchFileException("$tsConfigLocation not found")
val aliasPath = (resolvePath(tsConfig, tsConfigLocation) ?: if (config.typescript) {
resolvePath("tsconfig.app.json", "tsconfig.app.json")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class ISPPanelPopulator(private val project: Project) {
CoroutineScope(SupervisorJob() + Dispatchers.Default).async {
return@async Pair(
SourceScanner.findShadcnImplementation(project),
FileManager(project).getVirtualFilesByName("package.json").size
FileManager.getInstance(project).getVirtualFilesByName("package.json").size
)
}.asCompletableFuture().thenApplyAsync { (source, packageJsonCount) ->
log.info("Shadcn implementation detected: $source, package.json count: $packageJsonCount")
Expand Down

0 comments on commit 8b1d27c

Please sign in to comment.