Configurando um ambiente Windows para desenvolvimento
Tags: windows, tutorial, dotfiles, git
Published: 2021-09-08 01:01:57

## 💭 Introdução

Que atire o a primeira pedra o desenvolvedor que usa primariamente Windows que nunca enrolou pra atualizar ou formatar uma máquina por causa do Setup estar redondo... *salvo por aquele bug chato ou serviço travando a máquina toda 🤷‍♂️*

E isso é uma coisa que não tem como argumentar (*ainda*) que o pessoal primário Linux tem de mão beijada!

Mas e se eu te falasse que com um pouco de paciência, planejamento e ~~magia~~ scripts de Powershell conseguimos chegar a algo próximo? 

[Cover para o post via UnDraw](https://undraw.co/)

## 🤔 Planejando!

Antes de tudo temos de pensar:

> O que eu realmente preciso, do zero, em uma instalação nova do Windows?

Se questione, antes de partimos para as próximas etapas:

1. Qual **meu foco** primário?
2. Quais **ferramentas** preciso sempre?
3. Quais **linguagens** preciso sempre?
4. Quais **atalhos** gosto de usar sempre?
5. Quais **"frescuras"** instalo sempre?

As minhas respostas, em ordem:

1. Backend
2. Git, Powershell Core, Windows Terminal, SSH, Visual Studio Code, WSL, Docker
3. C#, Typescript
4. Meus atalhos de Git e Navegação terminal
5. oh-my-posh, posh-git, fontes com ligatures

Com base nessas respostas que vou pesar qual ferramentas de package irei utilizar e a prioridade!

Por exemplo apesar de *sempre* usar o Visual Studio em si sei que ele é mais demorado de instalar e, portanto, não ligo de precisar deixar ele rodando por mais tempo. Os outros ali da lista conseguem ir cobrindo a falta dele para as primeiras horas ou dia do novo setup!

### 1 - Escolhendo sua ferramentas para Packages

Para quem é acostumado com os `Nix` sabe que sempre tem um Package Manager da vida, o famoso `sudo apt-get install` (e similares, *nem tudo é apt-get*). Mas no Windows infelizmente estamos acostumados a sair caçando instaladores internet a fora, baixando, clicando em vários *Next* e só então vemos a coisa ser instalada.

Note que estou **focando nos ambientes comuns**. Existem soluções para **criar imagens inteiras do Windows** disponíveis para quem quer se dedicar a esse nível mas... quantas vezes você vai fazer isso fora de um ambiente empresarial?

> Para o seu ambiente pessoal o que é mais fácil? Manter uma imagem de instalação pronta ou configurar alguns scripts?

Felizmente a própria comunidade partiu pro ataque e surgiu com alguns soluções para Package Managers no Windows! Alguns deles são:

1. [Chocolatey](https://chocolatey.org/): Requer instalação (Powershell)
2. [Scoop](https://scoop.sh/): Requer instalação (Powershell)
3. [Winget](https://github.com/microsoft/winget-cli): Já incluso nas builds Insiders, passará a ser nativo no futuro, pode ser instalado pela Store

O que eles têm em comum? 

1. Todos contam com a comunidade para manter sua lista de packages atualizada
2. Todos são OpenSource

Então qual o grande diferencial? A quantidade de packages que cada um tem. Em números o **Chocolatey** toma a frente, seguido pelo **Winget** e pelo **Scoop**. Porém o **Winget se tornará nativo ao Windows em breve**, enquanto que os outros precisaram de passos adicionais.

### 2 - Escolhendo um Package Manager com base nas suas necessidades

Essa é uma escolha que você deverá fazer com base nas ferramentas que você utiliza no seu dia a dia. No meu caso, por utilizar várias ferramentas da Microsoft, vou de **winget**.

Como estou utilizando o `winget` vou pesquisando e salvando, em um `.txt` a lista de ferramentas que tenha disponíveis por ele e desejo instalar. Para isso executo o comando `winget search <nome_software>`, trocando as o campo `<nome_software>` pelo nome de o que gostaria de instalar, como o próprio SDK do dotnet.

![Buscando packages no Winget](https://dev-to-uploads.s3.amazonaws.com/i/n6qq2ecs0g6fht2d5lno.gif)

A seguinte lista é a que estou montando para a próxima vez que formatar meu laptop pessoal, todos estes são `id`s válidos do **winget**:

```
7zip.7zip
Mozilla.FirefoxDeveloperEdition
Microsoft.VisualStudioCode-User-x64
Git.Git
Microsoft.PowerShell
Microsoft.WindowsTerminal
Microsoft.dotnet
ditto.ditto
ShareX.ShareX
code52.Carnac
Microsoft.PowerToys
VideoLAN.VLC
``` 

A lista é "pequena" mas lembre-se: Estou focando apenas no absolutamente essencial para que eu comece a trabalhar/estudar utilizando o ambiente. O Docker, Visual Studio e WSL terão de vir depois.

## 🛠 Preparando!

### 3 - Automatizando os básicos

Como estamos falando do Windows devemos lembrar que **o Powershell é uma grande ferramenta** e seu amigo nas horas em que precisa automatizar algo! Ele não é tão difundido quanto os `shell scripts` mas ele é capaz de **muita coisa**!

Meu primeiro script de automação do setup vai ser um bem básico, seguindo o seguinte algoritmo:

1. Verifique se o `winget` está disponível, se sim continue
2. Pegue um arquivo `.txt`
3. Carregue o conteúdo, linha a linha
4. Para cada linha, em ordem de leitura:
  a. Execute `winget install -e --id $linha`

A implementação final é essa aqui, junto com o arquivo que mostrei acima com os IDs:

```{powershell}
$SoftwareListFile = ".\software_list.txt"
[string[]]$SoftwareList = Get-Content $SoftwareListFile

<#
.SYNOPSIS
    Checks if a Command is currently available on Powershell
#>
function Test-CommandExists {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]$testCommand
    )

    try {
        Get-Command $testCommand -ErrorAction Stop
        return $true
    }
    catch {
        return $false
    }
}

if (!(Test-CommandExists winget)) {
    Write-Host "Winget not found, unable to continue"
    Write-Host "Check on https://github.com/microsoft/winget-cli for instructions"
    return -1
}

Write-Output "This script will attempt to install multiple softwares on your system"
$DoInstall = Read-Host -Prompt "Are you sure you want to install? If so, type 'install' bellow."
$WingetCommandParam = ($DoInstall -eq "install") ? $DoInstall : "search";

$SoftwareList
| ForEach-Object -Process {
    &winget $WingetCommandParam -e --id $_
}

Write-Output "Done!"
if (!(Test-Path "${PSScriptRoot}\bootstrap.ps1" -PathType Leaf)) {
    return;
}

$DoBootstrap = Read-Host -Prompt "Type 'bootstrap' bellow if you want to run dotfiles' bootstrap as well"
if ($DoBootstrap -eq "bootstrap") {
    . "${PSScriptRoot}\bootstrap.ps1"
}
```

Para quem não está acostumado com *powershell* pode parecer um pouco grego, mas acredite: Não tem nada ali que não seja explicado por um `help <comando>` no Powershell e a estrutura é **bem parecida com o algoritmo**, salvo a quantidade de outputs que faço!

Agora podemos ir para o próximo passo: preparar nossos `dotfiles`.

### 4 - `dotfiles` no Windows

"Mas o que são `dotfiles`, Rodolpho?"

> `dotfiles` são arquivos que normalmente começam com . (algo oculto no Unix) e, normalmente, armazenam alguma configuração.

Alguns `dotfiles` famosos e suas aplicações são:

1. `.gitignore`: Configura os arquivos que devem ser ignorados em um repositório *Git*
2. `.gitconfig`: Configurações do seu usuário, normalmente encontrado em `~/.gitconfig` (mesmo no Windows!)
3. `.bashrc`: Configuração do Bash. No caso do Powershell substituímos esse aqui pelo `Profile.ps1`!

Se você programa provavelmente vai ter um `.gitconfig` mesmo que nunca o tenha criado manualmente, pois os comandos `git config --global` normalmente acabam gerando o arquivo para você 🙂.

Explicarei na próxima seção a ideia do `$PROFILE`, mas para finalizarmos sobre `dotfiles` vamos gravar o conceito:

> Um repositório de `dotfiles` contem arquivos de configurações que você quer compartilhar entre ambientes e um script (`.sh` ou `.ps1`) que gera links simbólicos (*são tipo atalhos, mas pra gente grande*) entre os arquivos do repositório e os arquivos armazenados no sistema operacional.

Ou seja, uma vez criado seu `dotfiles`, você só precisa fazer um `git pull`, `./script_que_cria_links.ps1` e sua máquina está sincronizada com o que quer que vc tenha colocado no repositório.

#### O PROFILE do Powershell

Quanto ao `Profile.ps1` você provavelmente o acessará através do powershell com o comando `code|vi|vim|nvim $PROFILE` (só tire dali os editores que você não usa).

> O `$PROFILE` é um arquivo que é executado **sempre que você abre um powershell**. Normalmente ele conterá atalhos, importações de módulos e verificações de que algo está disponível ou não.

O meu `$PROFILE` normalmente contem uma série de **atalhos do Git**, **ativação de Modules**, **verificações do ambiente**, **atalhos para navegação** e **segredos específicos do Powershell**.

Um pequeno trecho do meu `$PROFILE`:

```{powershell}
# All Shortcuts
Set-Alias -Name "back" -Value Pop-Location
Set-Alias -Name "push" -Value Push-Location
Set-Alias -Name "touch" -Value New-Item
Set-Alias -Name "open" -Value Invoke-Item

<#
.SYNOPSIS
    Calls fetches and pulls updates from the upstream branch. Stashes and Pops if there are uncomitted changes
.DESCRIPTION
    Shortcut function for calling git fetch and git pull while keeping uncomitted changes
#>
function Invoke-Git-FetchAndPull {
    git fetch --all
    git diff --exit-code
    $hasDiff = $LASTEXITCODE
    if ($hasDiff) {
        git stash
    }
    git pull
    if ($hasDiff) {
        git stash pop
    }
}

<#
.SYNOPSIS
    Calls fetch and then rebases into the target branch
.DESCRIPTION
    Shortcut function for calling git fetch and git rebase -i
.PARAMETER TargetBranch
    The branch to rebase on, defaults to origin/develop
#>
Function Invoke-Git-FetchAndRebase {
    [CmdletBinding()]
    param (
        [Parameter(HelpMessage = "The branch to rebase on, defaults to origin/develop")]
        [string]
        $TargetBranch = "origin/develop"
    )
    git fetch --all
    git rebase -i $TargetBranch
}

# Attempt to load posh-git
try {
    Import-Module posh-git
}
catch {
    Write-Error "Unable to Import-Module posh-git, it wasn't found"
}

# Checks if SSH Agent is running and git is configured
    try {
        $sshAgentStatus = (Get-Service -Name "ssh-agent").Status
        if ($sshAgentStatus -ne "Running") {
            Write-Warning "ssh-agent isn't running, you should change its initialization"
        }
        if ($null -eq $GitSshConfig) {
            Write-Warning "GIT_SSH isn't set, it might not use windows' OpenSSH"
        }
    }
    catch {
        Write-Warning "Unable to check on ssh-agent status"
    }
```

Como eu tenho **vários** atalhos, para mim, é vantajoso manter uma cópia deste perfil no meu `dotfiles` para que eu consiga ter a mesma produtividade em todo ambiente meu que tiver *Powershell*.

Caso você queira uma base para começar seu `dotfiles` para Windows pode dar uma olhada no meu repositório abaixo 👇

{% github rodolphocastro/dotfiles %}

## ▶ Executando!

Tudo planejado, salvo em um pen drive e/ou na nuvem? Hora de botar a mão na massa!

### 5 - Rodando scripts

O primeiro passo pra sair rodando coisas num Powershell zerado é ajustar a `ExecutionPolicy` da sua sessão.

O comando `Get-ExecutionPolicy` irá te dizer qual o atual nível. Para você fazer alterações normalmente quer defini-la (`Set-ExecutionPolicy`) como `Bypass` ou `RemoteUnsigned` com o `-Scope Process`. Traduzindo: **você irá permitir que o atual powershell que você está executando faça mais alterações que o normal**.

Feito isso é só partir para o abraço e rodar o script que fizemos na seção acima para instalar seus softwares.

### 6 - Baixando nossos `dotfiles`

Tudo instalado? Hora de fazer um `git clone <seu_repositório_dotfiles>`, entrar no repositório e executar o script `bootstrap.ps1`!

### 7 - Usando o OpenSSH do Windows 10 com o Git

É curioso como algo tão útil passa tão batido. Porém o **Windows 10 possui uma versão do OpenSSH embutida!**

Você não precisa usar um cliente de terceiros para poder usufruir do `ssh` com o *Git*. Basta fazer alguns ajustes:

1. Colocar o OpenSSH Agent para executar
  a. Você pode fazer isso via Powershell ou via Serviços do Windows
2. Criar um par de chaves
3. Adicionar essas chaves ao OpenSSH Agent
4. Cadastrar a chave pública com o seu Repositório Remoto
5. Ajustar uma variável de ambiente

Irei pular o item #4 pois isso vai ser específico do seu servidor. Seja ele um GitHub, GitLab, BitBucket ou Gitea.

#### Ligando o OpenSSH Agent

##### Com Powershell

Para os fãs de Powershell basta rodar esse script numa instância de admin:

```powershell
# Busca o serviço do windows chamado ssh-agent
$sshAgentService = Get-Service -Name "ssh-agent"
# Se o serviço não estiver iniciando com delay...
if ($sshAgentService.StartType -ne "AutomaticDelayedStart") {
    Write-Warning "Setting SSH Agent to DelayedStart"
    # Mande ele iniciar com delay!
    Set-Service -Name "ssh-agent" -StartupType AutomaticDelayedStart
}
```

##### Sem Powershell

Para quem não é fã do Powershell:

Abra o *Executar* (Atalho: Win+R) e digite `services.msc`.

Ordene a lista por nome e encontre um serviço chamado "OpenSSH Authentication Agent", dê um clique-duplo nele.

Na tela de propriedades altere o "Startup Type" para "Automatic (Delayed Start)", conforme:

![Propriedades do OpenSSH Agent](https://dev-to-uploads.s3.amazonaws.com/i/9p90gpc9jp9ff63epyj9.png)

Clique em *Apply* e *Ok*.

#### Criando e Adicionando Chaves SSH

Através de um terminal execute o seguinte comando, substituindo pelo seu email:

`ssh-keygen -o -a 100 -t ed25519 -C "meu-email@gmail.com"`

Isso irá criar um par de chaves `ED25519` no diretório `~/.ssh`, uma com o final `.pub` (*Spoiler: Essa é a que você copia e cola no seu servidor!*).

Agora para cadastrar sua chave com o OpenSSH Agent rode `ssh-add.exe` e confirme a senha da sua chave. Você verá algo como no gif abaixo:

![Adicionando chaves ao OpenSSH agent](https://dev-to-uploads.s3.amazonaws.com/i/lbd357mmj1n2fabnqpal.gif)

A mensagem "Identity added" é a indicação de que tudo deu certo.

#### Dizendo para o Git usar o OpenSSH

Finalmente só nos resta dizer para o *Git*: "*ow, usa isso aqui ao invés do seu ssh embutido!*".

Existem várias maneiras de fazer isso. Por `.gitconfig`, por links simbólicos e tudo. Mas, nas versões mais recentes do Git, temos uma maneira bem menos invasiva: Variáveis de ambiente.

Antes de tudo você precisa encontrar onde está o `ssh.exe` do Windows. Pra pegar o da sua máquina rode em um powershell:

```powershell
# Encontrando o comando "ssh" e pegando seu path
(Get-Command ssh).Path
# A output provavelmente será C:\WINDOWS\System32\OpenSSH\ssh.exe
```

Com esta output em mãos só nos resta agora **alterar a variável de ambiente GIT_SSH para `C:\WINDOWS\System32\OpenSSH\ssh.exe`**!

Pelo Windows 10/11:

Digite no menu iniciar "Variáveis" ou "Environment"

![pesquisando por environment no iniciar](https://dev-to-uploads.s3.amazonaws.com/i/cg4vi9n2ai280nh2v79c.png)

Selecione o primeiro item e, na nova tela, clique em "Variáveis de Ambiente|Environment Variables..." no canto direito inferior

![configurações do sistema](https://dev-to-uploads.s3.amazonaws.com/i/nbr63psvh2gyymt95dy2.png) 

Em "System Variables" clique em "New", chame a variável de "GIT_SSH" e insira o valor que pegamos no powershell.

![criando a variavel git_ssh](https://dev-to-uploads.s3.amazonaws.com/i/0bnqst22qmuf2z9nsews.png)

Pronto. Para testar se funcionou faça um `git clone` com ssh. Você provavelmente não terá de digitar sua senha da chave! 

> *Dica*: Além de funcionar para o *Git* o ssh-agent também estará funcionando para você configurar seus acessos por ssh para servidores!

### 8 - Windows Subsystem for Linux (WSL)

Tem coisas que só fazem *bloat* no Windows ou não dão aquela experiência legal, né? Eu, por exemplo, evito ao máximo instalar o `node` direto no meu Windows pois a experiência no Linux é simplesmente melhor!

Por muitos anos, antes do Windows 10, isso significava ter uma Máquina Virtual (normalmente no VirtualBox) e conectar nessa máquina pra, então, abrir uma IDE/Text Editor. Porém agora temos a possibilidade de executar o Linux dentro do próprio Windows (*edição Home ou maior*)!

Para isso basta **instalar o Windows Subsystem for Linux (WSL)**, instalar sua distro favorita e partir pro abraço! Você terá acesso ao `bash` diretamente do seu Powershell.

As intruções completas (oficiais) podem ser encontradas [neste link](https://docs.microsoft.com/en-us/windows/wsl/install-win10).

#### Habilitando o Windows Subsystem for Linux

##### Pré-Requisitos

Antes de tudo verifique se seu Windows está na versão certa! O WSL requer no mínimo a **build 18362** do Windows 10 **1903**.

Outra coisa importante é que **seu setup deve permitir virtualização!** Isso normalmente **será habilitado pela sua BIOS**. É raro isso estar bloqueado mas já vi equipamentos que bloqueavam ou ocultavam a possibilidade de ativar virtualização...

##### Com Powershell

Com Powershell basta você abrir um *prompt de Administrador* e executar:

`dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart`

E pronto! O Windows vai ativar a funcionalidade pra você.

##### Sem Powershell

Sem Powershell você terá de pesquisar, no iniciar, por "Features" e achar o "Turn Windows features on or off".

Dentro da janela de Features localize o WSL, marque-o, e clique em Ok. O Windows então instalará a feature para você!

![ativando wsl pelas features](https://dev-to-uploads.s3.amazonaws.com/i/zj6ku06nbd7m1l565gg4.png)

#### Habilitando Virtualização no Windows

##### Com Powershell

Novamente em um Powershell de Administradores, execute:

`dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart`

##### Sem Powershell

Novamente lá na tela de "Turn Windows features on or off", encontre e marque a opção "Virtual Machine Platform":

![ativando VMs do Windows](https://dev-to-uploads.s3.amazonaws.com/i/3r1amkwk5m8cnpfsv7wt.png)

#### Atualizando o Kernel do Linux

[Localize](https://docs.microsoft.com/en-us/windows/wsl/install-win10#step-4---download-the-linux-kernel-update-package) e [baixe](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi) o Kernel mais recente do Linux para WSL.

#### Ativando o WSL2

Finalmente podemos ativar o WSL2, esse passo só pode ser executado pelo Powershell:

`wsl --set-default-version 2`

Pronto! O WSL estará pronto para você utilizar após um reboot da máquina!

#### Instalando sua Distro favorita

Você agora poderá instalar as Distros de Linux [presentes na Windows Store](https://aka.ms/wslstore) ou através do `winget`!

Algumas distros que estão disponíveis são:

1. Ubuntu
2. Debian
3. Alpine
4. openSUSE

Agora é uma questão de você escolher a sua favorita, instalar, abrir o terminal e digitar `wsl` para lançar uma sessão no bash da sua distro!

### 9 - Docker Desktop

Quando comecei a escrever este Post (faz um tempo! Ele está como rascunho a meses já!) o processo era um pouco mais complicado 😅

Porém, hoje em dia, colocar o **Docker Desktop** para rodar, em sua máquina Windows, é pra lá de tranquilo.

Se você tiver acesso ao "winget" (recomendo!) basta rodar um `winget install DockerDesktop` e seguir as instruções na tela.

Se você quiser seguir pelo método old-school, acesse o [site oficial do Docker Desktop](https://www.docker.com/products/docker-desktop) e clique em "Download for Windows".

#### Alterações recentes (2021) na licença do Docker Desktop

Para quem está fora do loop: No final de Agosto de 2021 a equipe do Docker alterou a licença do Docker Desktop. ([Link da notícia oficial](https://www.docker.com/blog/updating-product-subscriptions/))

Para o seu uso pessoal pode ficar tranquilo. Salvo que você fature, como indivíduo, mais de U$ 10 milhões ao ano) essas alterações na licença deverão impactar *apenas empresas de grande porte*.

Em resumo, se na sua organização:

+ **ou** tem mais de 250 funcionários
+ **ou** fatura um montante que ultrapassa U$ 10 milhões

**Você terá de pagar para poder utilizar o Docker Desktop** para Windows ou MacOS.

### Notas Finais

Muito do que eu falei aqui provavelmente ficará desatualizado quando, finalmente, recebermos o Windows 11 em Outubro/2021!

Mas, até lá, sinta-se à vontade para utilizar este post como uma base para configurar seu ambiente Windows. (Diga-se de passagem, eu mesmo tenho utilizado esse artigo, mesmo em rascunho, sempre que reinstalo o Windows em um de meus computadores)

Outra recomendação, e esta será atualizada para o Windows 11, é buscar no [GitHub](https://github.com/) repositórios que tenham *dotfiles* para ambientes Windows. O meu repositório de dotfiles está disponível lá! 👇

{% github rodolphocastro/dotfiles %}