All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.jetbrains.plugin.structure.base.utils.FileUtil.kt Maven / Gradle / Ivy

Go to download

Base library for parsing JetBrains plugins. Used by other JetBrains Plugins structure libraries.

There is a newer version: 3.290
Show newest version
/*
 * Copyright 2000-2020 JetBrains s.r.o. and other contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
 */

package com.jetbrains.plugin.structure.base.utils

import com.jetbrains.plugin.structure.base.telemetry.UNKNOWN_SIZE
import org.slf4j.LoggerFactory
import java.io.*
import java.nio.charset.Charset
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import java.util.*
import java.util.stream.Collectors
import kotlin.streams.toList

private val LOG = LoggerFactory.getLogger("structure.FileUtil")

typealias Bytes = Long

fun Path.isZip(): Boolean = this.hasExtension("zip")

fun Path.isJar(): Boolean = this.hasExtension("jar")

fun Path.hasExtension(expected: String) =
  Files.isRegularFile(this) && expected == extension

fun Path.listRecursivelyAllFilesWithExtension(extension: String) =
  Files.walk(this, FileVisitOption.FOLLOW_LINKS).use { stream -> stream.filter { it.toString().endsWith(".${extension}") }.toList() }

fun String.withPathSeparatorOf(path: Path) = replace('\\', '/').replace("/", path.fileSystem.separator)
fun String.withZipFsSeparator() = replace('\\', '/')

fun String.toSystemIndependentName() = replace('\\', '/')
fun String.toSystemDependentName() = replace("/", FileSystems.getDefault().separator)

fun String.replaceInvalidFileNameCharacters(): String = replace(Regex("[^a-zA-Z0-9.#\\-() ]"), "_")

fun Path.inputStream(): InputStream = Files.newInputStream(this)

fun Path.outputStream(): OutputStream = Files.newOutputStream(this)

fun Path.writeText(text: String, charset: Charset = Charsets.UTF_8) = this.writeBytes(text.toByteArray(charset))

fun Path.readText(charset: Charset = Charsets.UTF_8) = String(Files.readAllBytes(this), charset)

fun Path.readLines(charset: Charset = Charsets.UTF_8): List {
  val result = ArrayList()
  forEachLine(charset) { result.add(it); }
  return result
}

fun Path.forEachLine(charset: Charset = Charsets.UTF_8, action: (line: String) -> Unit) {
  // Note: close is called at forEachLine
  BufferedReader(InputStreamReader(Files.newInputStream(this), charset)).forEachLine(action)
}

fun Path.readBytes(): ByteArray = Files.readAllBytes(this)

fun Path.writeBytes(bytes: ByteArray) {
  Files.write(this, bytes)
}

fun Path.createDir(): Path {
  Files.createDirectories(this)
  return this
}

fun Path.create(): Path {
  if (this.parent != null) {
    Files.createDirectories(this.parent)
  }
  Files.createFile(this)
  return this
}

fun Path.createParentDirs() {
  parent?.createDir()
}

fun Path.forceDeleteIfExists() {
  if (Files.exists(this)) {
    if (Files.isDirectory(this)) {
      this.forceRemoveDirectory()
    } else {
      Files.delete(this)
    }
  }
}

fun Path.deleteLogged() = try {
  forceDeleteIfExists()
  true
} catch (ie: InterruptedException) {
  Thread.currentThread().interrupt()
  LOG.info("Cannot delete file because of interruption:  $this")
  false
} catch (e: Exception) {
  LOG.error("Unable to delete $this", e)
  false
}

fun Path.exists(): Boolean = Files.exists(this)

fun Path.listFiles(): List {
  if (!this.isDirectory) {
    return emptyList()
  }
  return Files.list(this).use { it.collect(Collectors.toList()) }
}

fun Path.listJars(): List = listFiles().filter { it.isJar() }

fun Path.listAllFiles() =
  Files.walk(this).use { stream -> stream.filter { it.isFile }.map { this.relativize(it) }.toList() }

fun Path.deleteQuietly(): Boolean {
  return try {
    if (this.isDirectory) {
      this.forceRemoveDirectory()
    } else {
      Files.delete(this)
    }
    true
  } catch (ignored: Exception) {
    false
  }
}

fun Path.forceRemoveDirectory() {
  Files.walkFileTree(this, object : SimpleFileVisitor() {
    @Throws(IOException::class)
    override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
      Files.delete(file)
      return FileVisitResult.CONTINUE
    }

    @Throws(IOException::class)
    override fun postVisitDirectory(dir: Path, exc: IOException?): FileVisitResult {
      Files.delete(dir)
      return FileVisitResult.CONTINUE
    }
  })
}

val Path.isDirectory: Boolean
  get() = Files.isDirectory(this)

val Path.isFile: Boolean
  get() = Files.isRegularFile(this)

val Path.simpleName: String
  get() = (fileName ?: "").toString()

val Path.nameWithoutExtension: String
  get() = simpleName.substringBeforeLast(".")

val Path.extension: String
  get() = simpleName.substringAfterLast(".", "")

val Path.length: Long
  get() = Files.size(this)

val Path.pluginSize: Bytes
  get() = if (isZip() || isJar()) Files.size(this) else UNKNOWN_SIZE

val Path.description: String
  get() {
    return if (fileSystem == FileSystems.getDefault()) {
      toString()
    } else {
      "$fileSystem!$this"
    }
  }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy