diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..ad84532 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,13 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/README-PT.md b/README-PT.md deleted file mode 100644 index c60162d..0000000 --- a/README-PT.md +++ /dev/null @@ -1,149 +0,0 @@ -[english](README.md) | **português** - -# EnvManager - -Controle facilmente as propriedades do seu ambiente. - -### Instalação - -Para instalar, baixe o arquivo de instalação disponível em [releases](https://github.com/Irineu333/EnvManager/releases), -extraia e execute `install.sh` (Linux) com permissões de administrador. Para informações mais detalhadas consulte -as [instruções de instalação](src/dist/INSTALLATION). - -> **Compatibilidade:** GNU/Linux, Termux - -### Funcionamento - -O **EnvManager** é ideal para projetos com **múltiplos ambientes**, onde as variáveis são gerenciadas por um **arquivo -de propriedades** (denominado **target**) no formato `chave=valor`. Com o **EnvManager**, você pode alternar entre -diferentes ambientes e realizar outras manipulações **diretamente do terminal**. - -### Uso - -Após a instalação, o **EnvManager** é acessado pelo comando `envm`, seguido de um comando e seus argumentos. - -``` shell -$ envm [options] [arguments] -``` - -> **Opções:** --path=\, --version, --show-config - -Você pode obter as instruções de qualquer comando a opção `--help`. - -``` shell -$ envm --help -``` - -[Mais informações](docs/portuguese/envm.md) - -### Comandos Essenciais - -Esses comandos cobrem as principais funcionalidades para uso diário. - -#### install - -Inicialize o **EnvManager** no diretório do seu projeto com o comando `install`. - -``` shell -$ envm install -``` - -> **Opções:** --target=\, --force - -[Mais detalhes](docs/portuguese/install.md) - -#### save - -Salve as propriedades atuais como um ambiente usando `save`, seguido do nome do ambiente (denominado **tag**). - -``` shell -$ envm save -``` - -> **Opções:** --clipboard - -[Mais detalhes](docs/portuguese/save.md) - -#### list - -Liste os ambientes salvos com o comando `list`. - -``` shell -$ envm list -``` - -Para listar propriedades de um ambiente específico, adicione a **tag** após o comando. - -``` shell -$ envm list -``` - -> **Opções:** --current, --target - -[Mais detalhes](docs/portuguese/list.md) - -#### checkout - -Mude para um ambiente diferente com `checkout`. - -``` shell -$ envm checkout -``` - -> **Opções:** --force - -[Mais detalhes](docs/portuguese/checkout.md) - -#### delete - -Exclua um ou mais ambientes com `delete`. - -``` shell -$ envm delete -``` - -> **Opções:** --all - -[Mais detalhes](docs/portuguese/delete.md) - -### Outros Comandos - -#### set - -Adicione ou modifique propriedades com `set`. - -``` shell -$ envm set -``` - -> **Opções:** --tag=\, --all, --target-only - -[Mais detalhes](docs/portuguese/set.md) - -#### remove - -Remova propriedades específicas com `remove`. - -``` shell -$ envm remove -``` - -> **Opções:** --tag=\, --all, --target-only - -[Mais detalhes](docs/portuguese/remove.md) - -#### rename - -Renomeie um ambiente com `rename`. - -``` shell -$ envm rename -``` - -#### rollback - -Reverta alterações no **target**, sincronizando com o ambiente atual, usando `rollback`. - -``` shell -$ envm rollback -``` \ No newline at end of file diff --git a/README.md b/README.md index 3249d5b..ad22161 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -**english** | [português](README-PT.md) - # EnvManager Easily control your environment properties. @@ -34,7 +32,7 @@ You can get the instructions for any command with the `--help` option. $ envm --help ``` -[More information](docs/english/envm.md) +[More information](docs/envm.md) ### Essential Commands @@ -50,7 +48,7 @@ $ envm install > **Options:** --target=, --force -[More details](docs/english/install.md) +[More details](docs/install.md) #### save @@ -62,7 +60,7 @@ $ envm save > **Options:** --clipboard -[More details](docs/english/save.md) +[More details](docs/save.md) #### list @@ -80,7 +78,7 @@ $ envm list > **Options:** --current, --target -[More details](docs/english/list.md) +[More details](docs/list.md) #### checkout @@ -92,7 +90,7 @@ $ envm checkout > **Options:** --force -[More details](docs/english/checkout.md) +[More details](docs/checkout.md) #### delete @@ -104,7 +102,7 @@ $ envm delete > **Options:** --all -[More details](docs/english/delete.md) +[More details](docs/delete.md) ### Other Commands @@ -118,7 +116,7 @@ $ envm set > **Options:** --tag=, --all, --target-only -[More details](docs/english/set.md) +[More details](docs/set.md) #### remove @@ -130,7 +128,7 @@ $ envm remove > **Options:** --tag=, --all, --target-only -[More details](docs/english/remove.md) +[More details](docs/remove.md) #### rename @@ -148,5 +146,6 @@ Revert changes in the **target**, synchronizing with the current environment, us $ envm rollback ``` ---- -Translated from [README-PT.md](README-PT.md) using [ChatGPT](https://chat.openai.com/share/9d76f100-2955-4e01-b5d9-5dc10ee9b6de) \ No newline at end of file +### Others commands + +See the documentation for the other commands at [docs](/docs). \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index aae5f6d..1e7a8c3 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { } group = "com.neo.envmanager" -version = "1.0.0" +version = "1.1.0" repositories { mavenCentral() diff --git a/docs/english/checkout.md b/docs/checkout.md similarity index 100% rename from docs/english/checkout.md rename to docs/checkout.md diff --git a/docs/english/delete.md b/docs/delete.md similarity index 100% rename from docs/english/delete.md rename to docs/delete.md diff --git a/docs/english/envm.md b/docs/envm.md similarity index 100% rename from docs/english/envm.md rename to docs/envm.md diff --git a/docs/export.md b/docs/export.md new file mode 100644 index 0000000..b398805 --- /dev/null +++ b/docs/export.md @@ -0,0 +1,26 @@ +# `export` command + +Use the `export` command to export environments to a `.envm` file. + +**Export all environments:** + +```shell +$ envm export +``` + +**Export specific tags:** + +```shell +$ envm export +``` +> **Note:** You can export multiple environments by separating the tags with a space. + +## Options + +### `--output` + +Specify the output directory of the environments file; if not specified, will be prompt for it during export. + +```shell +$ envm export --output= +``` \ No newline at end of file diff --git a/docs/import.md b/docs/import.md new file mode 100644 index 0000000..69feccd --- /dev/null +++ b/docs/import.md @@ -0,0 +1,7 @@ +# `import` command + +Use the `import` command to import environments from a `.envm` file. + +```shell +$ envm import +``` \ No newline at end of file diff --git a/docs/english/install.md b/docs/install.md similarity index 96% rename from docs/english/install.md rename to docs/install.md index ea65ec6..3736ac5 100644 --- a/docs/english/install.md +++ b/docs/install.md @@ -8,7 +8,7 @@ $ envm install [options] ## Options -### `--target` or `-t` +### `--target` Sets the path of the target properties file (`target`). If not specified, **EnvManager** will prompt for it during installation. diff --git a/docs/english/list.md b/docs/list.md similarity index 100% rename from docs/english/list.md rename to docs/list.md diff --git a/docs/portuguese/checkout.md b/docs/portuguese/checkout.md deleted file mode 100644 index a0ca01b..0000000 --- a/docs/portuguese/checkout.md +++ /dev/null @@ -1,23 +0,0 @@ -# Comando `checkout` - -Use o comando `checkout` para alternar entre os ambientes. - -```shell -$ envm checkout -``` - -Também pode ser usado para para criar um ambientes vazio utilizando a opção `-force`. - -```shell -$ envm checkout -force -``` - -## Opção - -### `-force` ou `-f` - -Força o checkout, criando um ambiente se não existir. - -```shell -$ envm checkout -force -``` \ No newline at end of file diff --git a/docs/portuguese/delete.md b/docs/portuguese/delete.md deleted file mode 100644 index d3501ee..0000000 --- a/docs/portuguese/delete.md +++ /dev/null @@ -1,19 +0,0 @@ -# Comando `delete` - -Use o comando `delete` para excluir um ou mais ambientes. - -**Deletando um ambiente:** - -``` shell -$ envm delete -``` -**Deletando vários ambientes:** - -``` shell -$ envm delete ... [opções] -``` - -## Opções - -### `--all` ou `-a` -Exclua todos os ambientes. \ No newline at end of file diff --git a/docs/portuguese/envm.md b/docs/portuguese/envm.md deleted file mode 100644 index e0a5731..0000000 --- a/docs/portuguese/envm.md +++ /dev/null @@ -1,30 +0,0 @@ -# Comando `envm` - -É o ponto central do **EnvManager**`, permitindo o acesso a todos os outros comandos disponíveis. - -```shell -$ envm [opções] [argumentos do comando] -``` - -## Opções - -### `--path` ou `-p` -Especifica o caminho do projeto onde o **EnvManager** está ou será instalado. O diretório atual é usado por padrão. - -```shell -$ envm --path=/projects/MyProject -``` - -### `--version` ou `-v` -Mostra a versão atual do **EnvManager**. - -```shell -$ envm --version -``` - -### `--show-config` ou `-c` -Exibe as informações do arquivo de configuração do **EnvManager**. - -```shell -$ envm --show-config -``` diff --git a/docs/portuguese/install.md b/docs/portuguese/install.md deleted file mode 100644 index 45bd311..0000000 --- a/docs/portuguese/install.md +++ /dev/null @@ -1,25 +0,0 @@ -# Comando `install` - -Use o comando `install` para inicializar o **EnvManager** em um diretório. Necessário para usar os demais comandos. - -```shell -$ envm install [opções] -``` - -## Opções - -### `--target` ou `-t` - -Define o caminho do arquivo de propriedades alvo (`target`). Se não especificado, o **EnvManager** solicitará durante a instalação. - -```shell -$ envm install --target=environment.properties -``` - -### `--force` ou `-f` - -Força a instalação do **EnvManager**, mesmo que um arquivo de configuração já esteja presente no diretório. Essa opção é útil para resolver problemas na instalação. - -```shell -$ envm install --force -``` \ No newline at end of file diff --git a/docs/portuguese/list.md b/docs/portuguese/list.md deleted file mode 100644 index 3ec6f84..0000000 --- a/docs/portuguese/list.md +++ /dev/null @@ -1,31 +0,0 @@ -# Comando `list` - -Use o comando `list` para exibir os ambientes salvos ou as propriedades de um ambiente específico. - -**Para listar todos os ambientes salvos:** - -```shell -$ envm list -``` - -**Para listar as propriedades de um ambiente específico:** - -```shell -$ envm list -``` - -## Opções - -### `--current` ou `-c` -Mostra as propriedades do ambiente atual, facilitando a visualização rápida da configuração em uso. - -```shell -$ envm list --current -``` - -### `--target` ou `-t` -Exibe as propriedades do arquivo de propriedades alvo (**target**). - -```shell -$ envm list --target -``` \ No newline at end of file diff --git a/docs/portuguese/remove.md b/docs/portuguese/remove.md deleted file mode 100644 index cecf73f..0000000 --- a/docs/portuguese/remove.md +++ /dev/null @@ -1,48 +0,0 @@ -# Comando `remove` - -Use o comando `remove` para excluir propriedades especificadas pelas suas chaves. - -**Para excluir uma única propriedade:** - -```shell -$ envm remove [opções] -``` - -**Para excluir múltiplas propriedades:** - -```shell -$ envm remove ... [opções] -``` - -## Opções - -### `--tag` ou `-t` -Especifica o ambiente alvo. Na ausência desta opção, o ambiente atual é utilizado. - -```shell -$ envm remove --tag= -``` - -### `--all` ou `-a` -Esta opção tem dois comportamentos, dependendo da presença de chaves: - -**Com chaves especificadas:**
-Remove as chaves fornecidas de todos os ambientes salvos. - - ```shell - $ envm remove --all - ``` - -**Sem chaves especificadas:**
-Exclui todas as propriedades do ambiente atual (ou especificado via `--tag`). - - ```shell - $ envm remove --all - ``` - -### `--target-only` ou `-o` -Restringe a remoção às chaves apenas ao arquivo de propriedades alvo (**target**), sem impactar os ambientes salvos. - -```shell -$ envm remove --target-only -``` \ No newline at end of file diff --git a/docs/portuguese/rename.md b/docs/portuguese/rename.md deleted file mode 100644 index 88e4341..0000000 --- a/docs/portuguese/rename.md +++ /dev/null @@ -1,7 +0,0 @@ -# Comando `rename` - -Renomeia um ambiente. - -``` shell -$ envm rename -``` \ No newline at end of file diff --git a/docs/portuguese/rollback.md b/docs/portuguese/rollback.md deleted file mode 100644 index 985e5eb..0000000 --- a/docs/portuguese/rollback.md +++ /dev/null @@ -1,7 +0,0 @@ -# Comando `rollback` - -Reverta as propriedades do **target** para o estado do ambiente atual. - -``` shell -$ envm rollback -``` \ No newline at end of file diff --git a/docs/portuguese/save.md b/docs/portuguese/save.md deleted file mode 100644 index 6de2c43..0000000 --- a/docs/portuguese/save.md +++ /dev/null @@ -1,24 +0,0 @@ -# Comando `save` - -Use o comando `save` para savar as propriedades do arquivo de propriedades alvo (**target**) no ambiente atual ou em um ambiente especificado após o comando. - -**Para salvar no ambiente atual:** - -```shell -$ envm save [opções] -``` - -**Para salvar em um ambiente específico:** - -```shell -$ envm save [opções] -``` - -## Opções - -### `--clipboard` ou `-c` -Captura as propriedades da área de transferência em vez de usar o arquivo **target**. - -```shell -$ envm save --clipboard -``` \ No newline at end of file diff --git a/docs/portuguese/set.md b/docs/portuguese/set.md deleted file mode 100644 index aff5c9b..0000000 --- a/docs/portuguese/set.md +++ /dev/null @@ -1,38 +0,0 @@ -# Comando `set` - -Use para adicionar ou modificar propriedades `set`. Você deve fornecer as propriedades no formato `chave=valor`, separadas por espaço. - -**Para definir uma única propriedade:** - -```shell -$ envm set KEY1=VALUE [opções] -``` - -**Para definir múltiplas propriedades simultaneamente:** - -```shell -$ envm set KEY1=VALUE1 KEY2=VALUE2 ... [opções] -``` - -## Opções - -### `--tag` ou `-t` -Permite especificar o ambiente alvo para as propriedades. Na ausência desta opção, o ambiente atual é utilizado. - -```shell -$ envm set --tag= -``` - -### `--all` ou `-a` -Aplica as propriedades fornecidas a todos os ambientes salvos, facilitando a sincronização de configurações entre diferentes contextos. - -```shell -$ envm set --all -``` - -### `--target-only` ou `-o` -Limita a adição ou modificação de propriedades ao arquivo de propriedades alvo (**target**), sem afetar as configurações dos ambientes salvos. Isso é útil para modificações temporárias. - -```shell -$ envm set --target-only -``` \ No newline at end of file diff --git a/docs/english/remove.md b/docs/remove.md similarity index 98% rename from docs/english/remove.md rename to docs/remove.md index 3c40429..c269dc1 100644 --- a/docs/english/remove.md +++ b/docs/remove.md @@ -16,7 +16,7 @@ $ envm remove ... [options] ## Options -### `--tag` or `-t` +### `--tag` Specifies the target environment. In the absence of this option, the current environment is used. ```shell diff --git a/docs/english/rename.md b/docs/rename.md similarity index 100% rename from docs/english/rename.md rename to docs/rename.md diff --git a/docs/english/rollback.md b/docs/rollback.md similarity index 100% rename from docs/english/rollback.md rename to docs/rollback.md diff --git a/docs/english/save.md b/docs/save.md similarity index 100% rename from docs/english/save.md rename to docs/save.md diff --git a/docs/english/set.md b/docs/set.md similarity index 98% rename from docs/english/set.md rename to docs/set.md index 8f52bc3..2a7021c 100644 --- a/docs/english/set.md +++ b/docs/set.md @@ -16,7 +16,7 @@ $ envm set KEY1=VALUE1 KEY2=VALUE2 ... [options] ## Options -### `--tag` or `-t` +### `--tag` Allows specifying the target environment for the properties. In the absence of this option, the current environment is used. ```shell diff --git a/src/main/kotlin/com/neo/envmanager/Envm.kt b/src/main/kotlin/com/neo/envmanager/Envm.kt index 1d20cef..6245dc5 100644 --- a/src/main/kotlin/com/neo/envmanager/Envm.kt +++ b/src/main/kotlin/com/neo/envmanager/Envm.kt @@ -7,7 +7,6 @@ import com.github.ajalt.clikt.parameters.options.default import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file -import com.github.ajalt.mordant.rendering.TextStyle import com.github.ajalt.mordant.rendering.TextStyles import com.neo.envmanager.command.* import com.neo.envmanager.model.Paths @@ -49,7 +48,9 @@ class Envm : CliktCommand( Rename(), Setter(), Remove(), - Rollback() + Rollback(), + Export(), + Import() ) } @@ -66,14 +67,18 @@ class Envm : CliktCommand( private fun printConfigAndExit() { - val config = requireInstall() + val installation = requireInstall() + val config = installation.config val dim = TextStyles.dim - val stringBuilder = StringBuilder("target: ${dim(config.targetPath)}") + val message = buildString { - config.currentEnv?.let { stringBuilder.append("\ncurrent: ${dim(it)}") } + append("target: ${dim(config.targetPath)}") - throw PrintCompletionMessage(stringBuilder.toString()) + config.currentEnv?.let { append("\ncurrent: ${dim(it)}") } + } + + throw PrintCompletionMessage(message) } } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/command/Checkout.kt b/src/main/kotlin/com/neo/envmanager/command/Checkout.kt index af0df0e..98881d8 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Checkout.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Checkout.kt @@ -1,15 +1,15 @@ package com.neo.envmanager.command +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.neo.envmanager.com.neo.envmanager.util.extension.update -import com.neo.envmanager.core.Command import com.neo.envmanager.model.Environment import com.neo.envmanager.model.Target import com.neo.envmanager.util.extension.requireInstall import com.neo.envmanager.util.extension.tag -class Checkout : Command( +class Checkout : CliktCommand( help = "Checkout an environment" ) { @@ -22,12 +22,20 @@ class Checkout : Command( override fun run() { - val config = requireInstall() + val installation = requireInstall() + + val config = installation.config val target = Target.getOrCreate(config.targetPath) + val environment = if (force) { + Environment.getOrCreate(installation.environmentsDir, tag) + } else { + Environment(installation.environmentsDir, tag) + } + target.write( - getEnvironment() + environment .read() .toProperties() ) @@ -38,13 +46,4 @@ class Checkout : Command( ) } } - - private fun getEnvironment(): Environment { - - return if (force) { - Environment.getOrCreate(paths.environmentsDir, tag) - } else { - Environment(paths.environmentsDir, tag) - } - } } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/command/Delete.kt b/src/main/kotlin/com/neo/envmanager/command/Delete.kt index c9bf849..4e0804c 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Delete.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Delete.kt @@ -1,6 +1,7 @@ package com.neo.envmanager.command import com.github.ajalt.clikt.core.Abort +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.multiple @@ -8,18 +9,18 @@ import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.mordant.terminal.YesNoPrompt import com.neo.envmanager.com.neo.envmanager.util.extension.update -import com.neo.envmanager.core.Command import com.neo.envmanager.exception.Cancel +import com.neo.envmanager.exception.error.NoEnvironmentsFound import com.neo.envmanager.exception.error.SpecifyEnvironmentError -import com.neo.envmanager.model.Config import com.neo.envmanager.model.Environment -import com.neo.envmanager.util.extension.deleteChildren +import com.neo.envmanager.model.Installation +import com.neo.envmanager.util.Constants import com.neo.envmanager.util.extension.requireInstall import com.neo.envmanager.util.extension.success import extension.getOrNull import extension.ifFailure -class Delete : Command( +class Delete : CliktCommand( help = "Delete one or more environments" ) { @@ -32,11 +33,11 @@ class Delete : Command( help = "Delete all environments" ).flag() - private lateinit var config: Config + private lateinit var installation: Installation override fun run() { - config = requireInstall() + installation = requireInstall() if (all) { deleteAll() @@ -54,7 +55,7 @@ class Delete : Command( val environments = tags.mapNotNull { tag -> Environment.getSafe( - dir = paths.environmentsDir, + dir = installation.environmentsDir, tag = tag ).ifFailure { echoFormattedHelp(error = it) @@ -65,7 +66,7 @@ class Delete : Command( environments.forEach { it.file.delete() } - val currentTag = config.currentEnv ?: return + val currentTag = installation.config.currentEnv ?: return val currentHasDeleted = environments.any { it.file.nameWithoutExtension == currentTag @@ -78,11 +79,15 @@ class Delete : Command( private fun deleteAll() { - val count = paths.environmentsDir.listFiles()?.size ?: 0 + val environments = installation.environmentsDir.listFiles { _, name -> + name.endsWith(Constants.DOT_JSON) + } ?: throw NoEnvironmentsFound() - if (YesNoPrompt("Delete all $count environment?", terminal).ask() != true) throw Cancel() + val mustDeleteMessage = "Delete all ${environments.size} environment?" - paths.environmentsDir.deleteChildren() + if (YesNoPrompt(mustDeleteMessage, terminal).ask() != true) throw Cancel() + + environments.forEach { it.delete() } clearCurrentEnvironment() @@ -90,7 +95,7 @@ class Delete : Command( } private fun clearCurrentEnvironment() { - config.update { + installation.config.update { it.copy( currentEnv = null ) diff --git a/src/main/kotlin/com/neo/envmanager/command/Export.kt b/src/main/kotlin/com/neo/envmanager/command/Export.kt new file mode 100644 index 0000000..b0bba3a --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/command/Export.kt @@ -0,0 +1,124 @@ +package com.neo.envmanager.command + +import com.github.ajalt.clikt.core.Abort +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.terminal +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.multiple +import com.github.ajalt.clikt.parameters.options.defaultLazy +import com.github.ajalt.clikt.parameters.options.option +import com.github.ajalt.clikt.parameters.types.file +import com.github.ajalt.mordant.terminal.YesNoPrompt +import com.neo.envmanager.com.neo.envmanager.util.NotBlankValidation +import com.neo.envmanager.com.neo.envmanager.util.extension.environments +import com.neo.envmanager.exception.error.NoEnvironmentsFound +import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.Installation +import com.neo.envmanager.model.Target +import com.neo.envmanager.util.extension.envm +import com.neo.envmanager.util.extension.promptFile +import com.neo.envmanager.util.extension.requireInstall +import com.neo.envmanager.util.extension.resolveCollision +import com.neo.envmanager.util.gson +import java.io.File + +class Export : CliktCommand( + help = "Export environments" +) { + + private val output by option( + names = arrayOf("--output"), + help = "Output directory" + ).file( + canBeDir = true, + canBeFile = false + ).defaultLazy { + terminal.promptFile( + text = "Output directory", + canBeDir = true, + canBeFile = false, + default = File("output") + ) + } + + private val tags by argument( + help = "Specific tag (optional" + ).multiple() + + private lateinit var installation: Installation + + override fun run() { + + installation = requireInstall() + + if (!output.exists()) { + + echo("Output directory '${output.path}' does not exist.") + + if (YesNoPrompt("Create it?", terminal).ask() != true) throw Abort() + + output.mkdirs() + } + + if (tags.isEmpty()) { + exportAllEnvironments() + return + } + + exportSpecificEnvironment() + } + + private fun exportAllEnvironments() { + + val environments = installation.environments() + + if (environments.isEmpty()) { + throw NoEnvironmentsFound() + } + + writeExportFile(environments) + } + + private fun exportSpecificEnvironment() { + + val environments = tags.map { + Environment(installation.environmentsDir, it) + } + + writeExportFile(environments) + } + + private fun writeExportFile( + environments: List + ) { + val name = when { + environments.size == 1 -> { + environments.single().tag + } + + tags.isEmpty() -> { + Target(installation.config.targetPath).name + } + + else -> { + checkNotNull( + terminal.prompt( + prompt = "Choose a name for the export file", + convert = NotBlankValidation + ) + ) + } + } + + output.resolve(name.envm).resolveCollision().writeText( + gson.toJson( + buildMap { + environments.forEach { + put(it.tag, it.read()) + } + } + ) + ) + } +} + diff --git a/src/main/kotlin/com/neo/envmanager/command/Import.kt b/src/main/kotlin/com/neo/envmanager/command/Import.kt new file mode 100644 index 0000000..4819fc8 --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/command/Import.kt @@ -0,0 +1,53 @@ +package com.neo.envmanager.command + +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.terminal +import com.github.ajalt.clikt.parameters.arguments.argument +import com.github.ajalt.clikt.parameters.arguments.validate +import com.github.ajalt.clikt.parameters.types.file +import com.github.ajalt.mordant.terminal.YesNoPrompt +import com.neo.envmanager.com.neo.envmanager.util.EnvironmentsFileValidation +import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.FilePromise +import com.neo.envmanager.util.Constants +import com.neo.envmanager.util.MapTypeToken +import com.neo.envmanager.util.extension.requireInstall +import com.neo.envmanager.util.gson + +class Import : CliktCommand( + help = "Import environments" +) { + + private val file by argument( + help = "Environment(s) file (${Constants.DOT_ENVM})" + ).file( + mustExist = true, + canBeDir = false, + canBeFile = true + ).validate(EnvironmentsFileValidation) + + override fun run() { + + val installation = requireInstall() + + val type = MapTypeToken>().type + + val environments = gson.fromJson>>(file.readText(), type) + + for ((tag, map) in environments) { + + val promise = FilePromise(installation.environmentsDir, tag) + + if (promise.exists()) { + + echo(message = "Environment '$tag' already exists.") + + val mustOverwriteMessage = "Do you want to overwrite it?" + + if (YesNoPrompt(mustOverwriteMessage, terminal).ask() != true) continue + } + + Environment.getOrCreate(promise).write(map) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/command/Install.kt b/src/main/kotlin/com/neo/envmanager/command/Install.kt index 75d276c..0997803 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Install.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Install.kt @@ -1,20 +1,22 @@ package com.neo.envmanager.command import com.github.ajalt.clikt.core.Abort +import com.github.ajalt.clikt.core.CliktCommand +import com.github.ajalt.clikt.core.requireObject import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.types.file import com.neo.envmanager.com.neo.envmanager.util.extension.update -import com.neo.envmanager.core.Command import com.neo.envmanager.model.Config +import com.neo.envmanager.model.Paths import com.neo.envmanager.model.Target import com.neo.envmanager.util.Constants import com.neo.envmanager.util.Instructions import com.neo.envmanager.util.extension.promptFile import com.neo.envmanager.util.extension.success -class Install : Command(help = "Install environment control") { +class Install : CliktCommand(help = "Install environment control") { private val mustForce by option( names = arrayOf("-f", "--force"), @@ -22,7 +24,7 @@ class Install : Command(help = "Install environment control") { ).flag() private val target by option( - names = arrayOf("-t", "--target"), + names = arrayOf("--target"), help = "Target (environment properties file)" ).file( mustExist = true, @@ -30,18 +32,22 @@ class Install : Command(help = "Install environment control") { canBeFile = true ) + private val paths by requireObject() + override fun run() { - if (!mustForce && paths.isInstalled()) { + if (!mustForce && paths.configFile.exists()) { echo(success(text = "Already installed")) throw Abort() } paths.installationDir.mkdir() + val config = createConfig() + createGitIgnore() - finished(createConfig()) + finished(config) } private fun finished(config: Config) { diff --git a/src/main/kotlin/com/neo/envmanager/command/Lister.kt b/src/main/kotlin/com/neo/envmanager/command/Lister.kt index 6ba6a34..5888162 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Lister.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Lister.kt @@ -1,6 +1,7 @@ package com.neo.envmanager.command import com.github.ajalt.clikt.core.Abort +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.arguments.optional import com.github.ajalt.clikt.parameters.options.flag @@ -8,11 +9,10 @@ import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.mordant.rendering.TextStyles import com.github.ajalt.mordant.widgets.Text import com.neo.envmanager.com.neo.envmanager.exception.error.NoCurrentEnvironment -import com.neo.envmanager.core.Command import com.neo.envmanager.exception.error.EnvironmentNotFound import com.neo.envmanager.exception.error.NoEnvironmentsFound -import com.neo.envmanager.model.Config import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.Installation import com.neo.envmanager.model.Target import com.neo.envmanager.util.Constants import com.neo.envmanager.util.Instructions @@ -22,7 +22,7 @@ import com.neo.envmanager.util.extension.tag import extension.getOrElse import java.io.File -class Lister : Command( +class Lister : CliktCommand( name = "list", help = "List environments or properties" ) { @@ -38,11 +38,11 @@ class Lister : Command( help = "Show target properties" ).flag() - private lateinit var config: Config + private lateinit var installation: Installation override fun run() { - config = requireInstall() + installation = requireInstall() if (target) { showTarget() @@ -51,7 +51,7 @@ class Lister : Command( if (current) { - val tag = config.currentEnv ?: throw NoCurrentEnvironment() + val tag = installation.config.currentEnv ?: throw NoCurrentEnvironment() echo(terminal.theme.info(text = "> $tag")) @@ -72,7 +72,7 @@ class Lister : Command( private fun showTarget() { - val target = Target(config.targetPath) + val target = Target(installation.config.targetPath) target.read().forEach { (key, value) -> @@ -87,7 +87,7 @@ class Lister : Command( private fun showEnvironmentByTag(tag: String) { val environment = Environment.getSafe( - dir = paths.environmentsDir, + dir = installation.environmentsDir, tag = tag ).getOrElse { @@ -109,7 +109,7 @@ class Lister : Command( private fun showAllEnvironments() { - val environments = paths.environmentsDir.listFiles { _, name -> + val environments = installation.environmentsDir.listFiles { _, name -> name.endsWith(Constants.DOT_JSON) } @@ -127,7 +127,7 @@ class Lister : Command( echo( Text( - if (tag == config.currentEnv) { + if (tag == installation.config.currentEnv) { TextStyles.bold( getCurrentName(environment) ) @@ -143,15 +143,13 @@ class Lister : Command( val tag = environment.nameWithoutExtension - val target = runCatching { - Target(config.targetPath) - }.getOrElse { + val target = Target.getSafe( + installation.config.targetPath + ).getOrElse { return tag } - if (environment.readAsMap() == target.read().toMap()) { - return tag - } + if (environment.readAsMap() == target.read().toMap()) return tag return "$tag*" } diff --git a/src/main/kotlin/com/neo/envmanager/command/Remove.kt b/src/main/kotlin/com/neo/envmanager/command/Remove.kt index 11af554..71c95ac 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Remove.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Remove.kt @@ -1,27 +1,26 @@ package com.neo.envmanager.command import com.github.ajalt.clikt.core.Abort +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.arguments.multiple import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.mordant.terminal.YesNoPrompt -import com.neo.envmanager.core.Command import com.neo.envmanager.exception.Cancel import com.neo.envmanager.exception.error.KeyNotFound import com.neo.envmanager.exception.error.NoEnvironmentsFound import com.neo.envmanager.exception.error.SpecifyEnvironmentError import com.neo.envmanager.exception.error.SpecifyKeysError -import com.neo.envmanager.model.Config import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.Installation import com.neo.envmanager.model.Target import com.neo.envmanager.util.Constants import com.neo.envmanager.util.extension.requireInstall -import extension.getOrThrow import java.util.* -class Remove : Command( +class Remove : CliktCommand( help = "Remove one or more properties" ) { @@ -30,7 +29,7 @@ class Remove : Command( ).multiple() private val tag by option( - names = arrayOf("-t", "--tag"), + names = arrayOf("--tag"), help = "Specified environment tag; current environment is used by default" ) @@ -44,11 +43,11 @@ class Remove : Command( help = "Remove from all environments or remove all properties" ).flag() - private lateinit var config: Config + private lateinit var installation: Installation override fun run() { - config = requireInstall() + installation = requireInstall() if (all && keys.isEmpty()) { clearProperties() @@ -64,7 +63,7 @@ class Remove : Command( // clear target - val target = Target(config.targetPath) + val target = Target(installation.config.targetPath) target.write(Properties()) @@ -73,9 +72,9 @@ class Remove : Command( // clear environment - val tag = tag ?: config.currentEnv ?: throw SpecifyEnvironmentError() + val tag = tag ?: installation.config.currentEnv ?: throw SpecifyEnvironmentError() - val environment = Environment(paths.environmentsDir, tag) + val environment = Environment(installation.environmentsDir, tag) val propertiesCount = environment.read().size @@ -85,8 +84,8 @@ class Remove : Command( environment.write(emptyMap()) - if (tag == config.currentEnv) { - updateTarget(tag) + if (tag == installation.config.currentEnv) { + environment.updateTarget() } } @@ -111,7 +110,7 @@ class Remove : Command( private fun removeFromAllEnvironments() { - val environments = paths.environmentsDir.listFiles { _, name -> + val environments = installation.environmentsDir.listFiles { _, name -> name.endsWith(Constants.DOT_JSON) } @@ -140,17 +139,17 @@ class Remove : Command( environment.write(properties) - if (tag == config.currentEnv) { - updateTarget(tag) + if (tag == installation.config.currentEnv) { + environment.updateTarget() } } } private fun removeFromEnvironment() { - val tag = tag ?: config.currentEnv ?: throw SpecifyEnvironmentError() + val tag = tag ?: installation.config.currentEnv ?: throw SpecifyEnvironmentError() - val environment = Environment(paths.environmentsDir, tag) + val environment = Environment(installation.environmentsDir, tag) val properties = environment.read().toMutableMap() @@ -170,14 +169,14 @@ class Remove : Command( environment.write(properties) // Checkout when set in current environment - if (tag == config.currentEnv) { - updateTarget(tag) + if (tag == installation.config.currentEnv) { + environment.updateTarget() } } private fun removeFromTarget() { - val target = Target(config.targetPath) + val target = Target(installation.config.targetPath) val properties = target.read() @@ -197,12 +196,10 @@ class Remove : Command( target.write(properties) } - private fun updateTarget(tag: String) { + private fun Environment.updateTarget() { - val target = Target(config.targetPath) + val target = Target(installation.config.targetPath) - val environment = Environment(paths.environmentsDir, tag) - - target.write(environment.read().toProperties()) + target.write(read().toProperties()) } } diff --git a/src/main/kotlin/com/neo/envmanager/command/Rename.kt b/src/main/kotlin/com/neo/envmanager/command/Rename.kt index aa4be2b..c2446fd 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Rename.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Rename.kt @@ -1,13 +1,12 @@ package com.neo.envmanager.command +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.neo.envmanager.com.neo.envmanager.util.extension.update -import com.neo.envmanager.core.Command import com.neo.envmanager.model.Environment import com.neo.envmanager.util.extension.requireInstall -import extension.getOrThrow -class Rename : Command( +class Rename : CliktCommand( help = "Rename an environment" ) { @@ -21,9 +20,9 @@ class Rename : Command( override fun run() { - val config = requireInstall() + val (config, environmentsDir) = requireInstall() - Environment(paths.environmentsDir, oldTag).renameTo(newTag) + Environment(environmentsDir, oldTag).renameTo(newTag) if (oldTag == config.currentEnv) { config.update { diff --git a/src/main/kotlin/com/neo/envmanager/command/Rollback.kt b/src/main/kotlin/com/neo/envmanager/command/Rollback.kt index 0c236ce..61d63ad 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Rollback.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Rollback.kt @@ -1,25 +1,24 @@ package com.neo.envmanager.command +import com.github.ajalt.clikt.core.CliktCommand import com.neo.envmanager.com.neo.envmanager.exception.error.NoCurrentEnvironment -import com.neo.envmanager.core.Command import com.neo.envmanager.model.Environment import com.neo.envmanager.model.Target import com.neo.envmanager.util.extension.requireInstall -import extension.getOrThrow -class Rollback : Command( +class Rollback : CliktCommand( help = "Rollback the target" ) { override fun run() { - val config = requireInstall() + val (config, environmentsDir) = requireInstall() val target = Target.getOrCreate(config.targetPath) val tag = config.currentEnv ?: throw NoCurrentEnvironment() - val environment = Environment(paths.environmentsDir, tag) + val environment = Environment(environmentsDir, tag) target.write(environment.read().toProperties()) } diff --git a/src/main/kotlin/com/neo/envmanager/command/Save.kt b/src/main/kotlin/com/neo/envmanager/command/Save.kt index e35ddbb..c565ab2 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Save.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Save.kt @@ -1,5 +1,6 @@ package com.neo.envmanager.command +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.arguments.optional import com.github.ajalt.clikt.parameters.options.flag @@ -7,13 +8,10 @@ import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.mordant.terminal.YesNoPrompt import com.neo.envmanager.com.neo.envmanager.util.extension.update import com.neo.envmanager.com.neo.envmanager.util.mutedErrorOutput -import com.neo.envmanager.core.Command import com.neo.envmanager.exception.Cancel import com.neo.envmanager.exception.error.NotSupportedTransferData import com.neo.envmanager.exception.error.SpecifyEnvironmentError -import com.neo.envmanager.model.Config -import com.neo.envmanager.model.Environment -import com.neo.envmanager.model.FilePromise +import com.neo.envmanager.model.* import com.neo.envmanager.model.Target import com.neo.envmanager.util.extension.requireInstall import com.neo.envmanager.util.extension.tag @@ -22,7 +20,7 @@ import java.awt.datatransfer.DataFlavor import java.io.ByteArrayInputStream import java.util.* -class Save : Command(help = "Save target to an environment") { +class Save : CliktCommand(help = "Save target to an environment") { private val tag by tag().optional() @@ -32,18 +30,18 @@ class Save : Command(help = "Save target to an environment") { help = "Save from clipboard" ).flag() - private lateinit var config: Config + private lateinit var installation: Installation override fun run() { - config = requireInstall() + val (config, environmentsDir) = requireInstall().also { installation = it } // Get tag from current environment or from argument val tag = tag ?: config.currentEnv ?: throw SpecifyEnvironmentError() val properties = getProperties() - val promise = FilePromise(paths.environmentsDir, tag) + val promise = FilePromise(environmentsDir, tag) if (promise.file.exists() && this.tag != null) { @@ -54,44 +52,40 @@ class Save : Command(help = "Save target to an environment") { if (overwritePrompt.ask() != true) throw Cancel() } - Environment - .getOrCreate(promise) - .write(properties.toMap()) + val environment = Environment.getOrCreate(promise) + + environment.write(properties.toMap()) // Update target when current environment is modified if (fromClipboard && tag == config.currentEnv) { - updateTarget(tag) + environment.updateTarget() return } // Checkout when save target without environment if (!fromClipboard && config.currentEnv == null) { - checkout(tag) + environment.checkout() } } - private fun checkout(tag: String) { + private fun Environment.checkout() { + + val tag = file.nameWithoutExtension - config.update { + installation.config.update { it.copy( currentEnv = tag ) } - updateTarget(tag) + updateTarget() } - private fun updateTarget(tag: String) { - - val target = Target(config.targetPath) + private fun Environment.updateTarget() { - val environment = Environment(paths.environmentsDir, tag) + val target = Target(installation.config.targetPath) - target.write( - environment - .read() - .toProperties() - ) + target.write(read().toProperties()) } private fun getProperties(): Properties { @@ -120,6 +114,6 @@ class Save : Command(help = "Save target to an environment") { } } - return Target(config.targetPath).read() + return Target(installation.config.targetPath).read() } } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/command/Setter.kt b/src/main/kotlin/com/neo/envmanager/command/Setter.kt index a62ea6d..3742339 100644 --- a/src/main/kotlin/com/neo/envmanager/command/Setter.kt +++ b/src/main/kotlin/com/neo/envmanager/command/Setter.kt @@ -1,21 +1,20 @@ package com.neo.envmanager.command +import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.options.flag import com.github.ajalt.clikt.parameters.options.option -import com.neo.envmanager.core.Command import com.neo.envmanager.exception.error.NoEnvironmentsFound import com.neo.envmanager.exception.error.SpecifyEnvironmentError -import com.neo.envmanager.model.Config import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.Installation import com.neo.envmanager.model.Target import com.neo.envmanager.util.Constants import com.neo.envmanager.util.extension.properties import com.neo.envmanager.util.extension.requireInstall -import extension.getOrThrow import java.util.* -class Setter : Command( +class Setter : CliktCommand( name = "set", help = "Set one or more properties", ) { @@ -26,7 +25,7 @@ class Setter : Command( ).properties(required = true) private val tag by option( - names = arrayOf("-t", "--tag"), + names = arrayOf("--tag"), help = "Specified environment tag; current environment is used by default" ) @@ -40,11 +39,11 @@ class Setter : Command( help = "Set to target only" ).flag() - private lateinit var config: Config + private lateinit var installation: Installation override fun run() { - config = requireInstall() + installation = requireInstall() if (targetOnly) { saveInTarget() @@ -61,7 +60,9 @@ class Setter : Command( private fun saveInTarget() { - Target(config.targetPath).add( + val target = Target(installation.config.targetPath) + + target.add( Properties().apply { putAll(properties) } @@ -70,7 +71,7 @@ class Setter : Command( private fun saveInAllEnvironments() { - val environments = paths.environmentsDir.listFiles { _, name -> + val environments = installation.environmentsDir.listFiles { _, name -> name.endsWith(Constants.DOT_JSON) } @@ -79,38 +80,38 @@ class Setter : Command( environments.forEach { Environment(it).add(properties.toMap()) } val mustCheckout = environments.any { - it.nameWithoutExtension == config.currentEnv + it.nameWithoutExtension == installation.config.currentEnv } if (mustCheckout) { - checkout(tag = config.currentEnv ?: return) + val tag = installation.config.currentEnv ?: return + + val environment = Environment.getOrCreate(installation.environmentsDir, tag) + + environment.checkout() } } private fun saveInEnvironment() { + val config = installation.config + val tag = tag ?: config.currentEnv ?: throw SpecifyEnvironmentError() - val environment = Environment.getOrCreate(paths.environmentsDir, tag) + val environment = Environment.getOrCreate(installation.environmentsDir, tag) environment.add(properties.toMap()) // Checkout when set in current environment if (tag == config.currentEnv) { - checkout(tag) + environment.checkout() } } - private fun checkout(tag: String) { - - val target = Target(config.targetPath) + private fun Environment.checkout() { - val environment = Environment.getOrCreate(paths.environmentsDir, tag) + val target = Target(installation.config.targetPath) - target.write( - environment - .read() - .toProperties() - ) + target.write(read().toProperties()) } } diff --git a/src/main/kotlin/com/neo/envmanager/core/Command.kt b/src/main/kotlin/com/neo/envmanager/core/Command.kt deleted file mode 100644 index d7efe95..0000000 --- a/src/main/kotlin/com/neo/envmanager/core/Command.kt +++ /dev/null @@ -1,14 +0,0 @@ -package com.neo.envmanager.core - -import com.github.ajalt.clikt.core.CliktCommand -import com.github.ajalt.clikt.core.requireObject -import com.github.ajalt.clikt.parameters.arguments.argument -import com.neo.envmanager.model.Paths - -abstract class Command( - name: String? = null, - help: String -) : CliktCommand(name = name, help = help) { - - protected val paths by requireObject() -} \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/model/Environment.kt b/src/main/kotlin/com/neo/envmanager/model/Environment.kt index 5d55b27..08bf1d7 100644 --- a/src/main/kotlin/com/neo/envmanager/model/Environment.kt +++ b/src/main/kotlin/com/neo/envmanager/model/Environment.kt @@ -1,17 +1,18 @@ package com.neo.envmanager.model import Resource -import com.google.gson.Gson import com.neo.envmanager.com.neo.envmanager.exception.error.EnvironmentAlreadyExists import com.neo.envmanager.exception.error.EnvironmentNotFound -import com.neo.envmanager.util.Constants import com.neo.envmanager.util.extension.json import com.neo.envmanager.util.extension.readAsMap +import com.neo.envmanager.util.gson import java.io.File @JvmInline value class Environment(val file: File) { + val tag get() = file.nameWithoutExtension + constructor(path: String) : this(File(path)) constructor(dir: File, tag: String) : this(dir.resolve(tag.json)) @@ -23,11 +24,9 @@ value class Environment(val file: File) { return file.readAsMap() } - fun write(properties: Map<*, *>) { - file.writeText( - Gson().toJson(properties) - ) - } + fun write(properties: Map<*, *>) = file.writeText( + gson.toJson(properties) + ) fun add(properties: Map<*, *>) { write(properties = read() + properties) diff --git a/src/main/kotlin/com/neo/envmanager/model/FilePromise.kt b/src/main/kotlin/com/neo/envmanager/model/FilePromise.kt index 491aff5..99be2ab 100644 --- a/src/main/kotlin/com/neo/envmanager/model/FilePromise.kt +++ b/src/main/kotlin/com/neo/envmanager/model/FilePromise.kt @@ -8,4 +8,6 @@ value class FilePromise(val file: File) { constructor(dir: File, tag: String) : this(dir.resolve(tag.json)) constructor(path: String) : this(File(path)) + + fun exists() = file.exists() } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/model/Installation.kt b/src/main/kotlin/com/neo/envmanager/model/Installation.kt new file mode 100644 index 0000000..17afc37 --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/model/Installation.kt @@ -0,0 +1,8 @@ +package com.neo.envmanager.model + +import java.io.File + +data class Installation( + val config: Config, + val environmentsDir: File +) \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/model/Paths.kt b/src/main/kotlin/com/neo/envmanager/model/Paths.kt index c64ea42..5e3c0cc 100644 --- a/src/main/kotlin/com/neo/envmanager/model/Paths.kt +++ b/src/main/kotlin/com/neo/envmanager/model/Paths.kt @@ -3,13 +3,10 @@ package com.neo.envmanager.model import com.neo.envmanager.util.Constants import java.io.File -class Paths( - val projectDir: File -) { +class Paths(val projectDir: File) { val installationDir = projectDir.resolve(Constants.INSTALL_FOLDER_PATH) val configFile = installationDir.resolve(Constants.CONFIG_FILE_PATH) val environmentsDir = installationDir.resolve(Constants.ENVIRONMENTS_FOLDER_PATH) - fun isInstalled() = configFile.exists() } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/model/Target.kt b/src/main/kotlin/com/neo/envmanager/model/Target.kt index 72d276d..1b671bf 100644 --- a/src/main/kotlin/com/neo/envmanager/model/Target.kt +++ b/src/main/kotlin/com/neo/envmanager/model/Target.kt @@ -1,5 +1,6 @@ package com.neo.envmanager.model +import Resource import com.neo.envmanager.exception.error.TargetNotFound import com.neo.envmanager.util.extension.iterable import java.io.File @@ -8,6 +9,8 @@ import java.util.* @JvmInline value class Target(val file: File) { + val name get() = file.nameWithoutExtension + constructor(path: String) : this(File(path)) init { @@ -34,6 +37,12 @@ value class Target(val file: File) { companion object { + fun getSafe(path: String) = try { + Resource.Result.Success(Target(File(path))) + } catch (e: TargetNotFound) { + Resource.Result.Failure(e) + } + fun getOrCreate(path: String) = getOrCreate(FilePromise(path)) private fun getOrCreate(promise: FilePromise): Target { diff --git a/src/main/kotlin/com/neo/envmanager/util/Constants.kt b/src/main/kotlin/com/neo/envmanager/util/Constants.kt index ebb464e..8de3c3a 100644 --- a/src/main/kotlin/com/neo/envmanager/util/Constants.kt +++ b/src/main/kotlin/com/neo/envmanager/util/Constants.kt @@ -7,6 +7,7 @@ object Constants { const val DOT_JSON = ".json" const val DOT_GITIGNORE = ".gitignore" + const val DOT_ENVM = ".envm" const val PROPERTY_SEPARATOR = " : " } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/Functions.kt b/src/main/kotlin/com/neo/envmanager/util/Functions.kt index 8da2378..de8539c 100644 --- a/src/main/kotlin/com/neo/envmanager/util/Functions.kt +++ b/src/main/kotlin/com/neo/envmanager/util/Functions.kt @@ -5,7 +5,7 @@ import java.io.PrintStream fun mutedErrorOutput( function: () -> R -) : R { +): R { val old = System.err System.setErr(PrintStream(OutputStream.nullOutputStream())) diff --git a/src/main/kotlin/com/neo/envmanager/util/Gson.kt b/src/main/kotlin/com/neo/envmanager/util/Gson.kt new file mode 100644 index 0000000..a6187ee --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/util/Gson.kt @@ -0,0 +1,8 @@ +package com.neo.envmanager.util + +import com.google.gson.Gson + +val gson = Gson() + .newBuilder() + .setPrettyPrinting() + .create() \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/MapTypeToken.kt b/src/main/kotlin/com/neo/envmanager/util/MapTypeToken.kt index 05bb595..4207aac 100644 --- a/src/main/kotlin/com/neo/envmanager/util/MapTypeToken.kt +++ b/src/main/kotlin/com/neo/envmanager/util/MapTypeToken.kt @@ -2,4 +2,4 @@ package com.neo.envmanager.util import com.google.gson.reflect.TypeToken -object MapTypeToken : TypeToken>() \ No newline at end of file +class MapTypeToken : TypeToken>() \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/Validations.kt b/src/main/kotlin/com/neo/envmanager/util/Validations.kt new file mode 100644 index 0000000..62f9704 --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/util/Validations.kt @@ -0,0 +1,20 @@ +package com.neo.envmanager.com.neo.envmanager.util + +import com.github.ajalt.clikt.parameters.arguments.ArgumentTransformContext +import com.github.ajalt.mordant.terminal.ConversionResult +import com.neo.envmanager.util.Constants +import java.io.File + +val NotBlankValidation = { input: String -> + if (input.isBlank()) { + ConversionResult.Invalid("Cannot be blank") + } else { + ConversionResult.Valid(input) + } +} + +val EnvironmentsFileValidation: ArgumentTransformContext.(File) -> Unit = { + if (!it.name.endsWith(Constants.DOT_ENVM)) { + fail("Invalid extension '${it.extension}'") + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/CliktCommand.kt b/src/main/kotlin/com/neo/envmanager/util/extension/CliktCommand.kt index 6272a14..b5f6ab5 100644 --- a/src/main/kotlin/com/neo/envmanager/util/extension/CliktCommand.kt +++ b/src/main/kotlin/com/neo/envmanager/util/extension/CliktCommand.kt @@ -4,17 +4,16 @@ import com.github.ajalt.clikt.core.Abort import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.core.terminal import com.github.ajalt.clikt.parameters.arguments.argument -import com.google.gson.Gson import com.neo.envmanager.exception.error.NotInstalledError -import com.neo.envmanager.model.Config +import com.neo.envmanager.model.Installation import com.neo.envmanager.model.Paths import com.neo.envmanager.util.Instructions -fun CliktCommand.requireInstall(): Config { +fun CliktCommand.requireInstall(): Installation { val paths = checkNotNull(currentContext.findObject()) - if (!paths.isInstalled()) { + if (!paths.configFile.exists()) { echoFormattedHelp(NotInstalledError()) echo(Instructions.INSTALL) @@ -22,7 +21,10 @@ fun CliktCommand.requireInstall(): Config { throw Abort() } - return paths.configFile.readAsConfig() + return Installation( + config = paths.configFile.readAsConfig(), + environmentsDir = paths.environmentsDir + ) } fun CliktCommand.tag() = argument( diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/Config.kt b/src/main/kotlin/com/neo/envmanager/util/extension/Config.kt index c5ce87c..376654f 100644 --- a/src/main/kotlin/com/neo/envmanager/util/extension/Config.kt +++ b/src/main/kotlin/com/neo/envmanager/util/extension/Config.kt @@ -1,9 +1,9 @@ package com.neo.envmanager.com.neo.envmanager.util.extension import com.github.ajalt.clikt.core.CliktCommand -import com.google.gson.Gson import com.neo.envmanager.model.Config import com.neo.envmanager.model.Paths +import com.neo.envmanager.util.gson context(CliktCommand) fun Config.update(block: (Config) -> Config = { it }): Config { @@ -12,7 +12,7 @@ fun Config.update(block: (Config) -> Config = { it }): Config { return block(this).also { paths.configFile.writeText( - Gson().toJson(it) + gson.toJson(it) ) } } \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/File.kt b/src/main/kotlin/com/neo/envmanager/util/extension/File.kt index a9eb21c..ab6600a 100644 --- a/src/main/kotlin/com/neo/envmanager/util/extension/File.kt +++ b/src/main/kotlin/com/neo/envmanager/util/extension/File.kt @@ -1,21 +1,14 @@ package com.neo.envmanager.util.extension -import com.google.gson.Gson -import com.neo.envmanager.util.MapTypeToken import com.neo.envmanager.model.Config +import com.neo.envmanager.util.Constants +import com.neo.envmanager.util.MapTypeToken +import com.neo.envmanager.util.gson import java.io.File -import java.util.* - -fun File.readAsProperties(): Properties { - - return Properties().apply { - load(inputStream()) - } -} fun File.readAsConfig(): Config { - return Gson().fromJson( + return gson.fromJson( readText(), Config::class.java ) @@ -23,14 +16,36 @@ fun File.readAsConfig(): Config { fun File.readAsMap(): Map { + val type = MapTypeToken().type + return runCatching> { - Gson().fromJson( + gson.fromJson( readText(), - MapTypeToken.type + type ) }.getOrElse { emptyMap() } } -fun File.deleteChildren() = listFiles()?.forEach { it.deleteRecursively() } \ No newline at end of file +fun File.jsonFiles(): Array { + + return listFiles { _, name -> + name.endsWith(Constants.DOT_JSON) + }.orEmpty() +} + +fun File.resolveCollision(): File { + + var file = this + var index = 0 + + val name = file.nameWithoutExtension + val extension = file.extension + + while (file.exists()) { + file = File(file.parent, "$name(${++index}).$extension") + } + + return file +} diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/Installation.kt b/src/main/kotlin/com/neo/envmanager/util/extension/Installation.kt new file mode 100644 index 0000000..14fdcdc --- /dev/null +++ b/src/main/kotlin/com/neo/envmanager/util/extension/Installation.kt @@ -0,0 +1,7 @@ +package com.neo.envmanager.com.neo.envmanager.util.extension + +import com.neo.envmanager.model.Environment +import com.neo.envmanager.model.Installation +import com.neo.envmanager.util.extension.jsonFiles + +fun Installation.environments() = environmentsDir.jsonFiles().map(::Environment) \ No newline at end of file diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/String.kt b/src/main/kotlin/com/neo/envmanager/util/extension/String.kt index 55e74ad..0ee57de 100644 --- a/src/main/kotlin/com/neo/envmanager/util/extension/String.kt +++ b/src/main/kotlin/com/neo/envmanager/util/extension/String.kt @@ -1,8 +1,10 @@ package com.neo.envmanager.util.extension import com.github.ajalt.clikt.core.UsageError +import com.neo.envmanager.util.Constants -val String.json get() = "$this.json" +val String.json get() = plus(Constants.DOT_JSON) +val String.envm get() = plus(Constants.DOT_ENVM) fun String.toPair( separator: String diff --git a/src/main/kotlin/com/neo/envmanager/util/extension/Terminal.kt b/src/main/kotlin/com/neo/envmanager/util/extension/Terminal.kt index 44847f1..05d9648 100644 --- a/src/main/kotlin/com/neo/envmanager/util/extension/Terminal.kt +++ b/src/main/kotlin/com/neo/envmanager/util/extension/Terminal.kt @@ -26,6 +26,10 @@ fun Terminal.promptFile( ConversionResult.Invalid("Path cannot be empty") } + input.isBlank() -> { + ConversionResult.Invalid("Path cannot be blank") + } + mustExist && !file.exists() -> { ConversionResult.Invalid("Path does not exist") }