Manjaro. Gestor de paquetes no funciona. Mensaje «Synchronizing package databases»

Al actualizar Manjaro llevaba un par de días que se me quedaba colgado con el mensaje «Synchronizing package databases».

Esto significa que la réplica (mirror) de los servidores que estás utilizando no está funcionando adecuadamente.

Técnicamente este es el comando que selecciona el mirror más rápido y sincroniza el sistema:

sudo pacman-mirrors --fasttrack && sudo pacman -Syyu

En mi caso siempre me estaba seleccionando el mismo servidor que ya tenía por lo que el problema persistía. Con lo que he decidido cambiar por los de otro país (Alemania):

sudo pacman-mirrors --country Germany && sudo pacman -Syyu

Con esto ya puedo actualizar.

Una forma de organizar la configuración de la shell

A medida que voy instalando herramientas de desarrollo como por ejemplo SDKMAN!, Anaconda, Node Version Manager, el fichero .zshrc va aumentando en tamaño y complejidad.

Para mantener cada una de estas configuraciones de forma independiente y poder compartirlas entre varios equipos lo que hago es tener un directorio ~/.aliases donde voy añadiendo un fichero *.aliases para cada configuración. Hay que remarcar que no hay problema en aplicar esta solución si en lugar de zsh usamos bash.

Este directorio lo tengo sincronizado entre varios equipos a través de git y gitlab.com.

En el fichero ~/.zshrc, al final de todo, he añadido las siguientes líneas. Estas línea le indican a la shell que ejecute todos los scripts con extensión *.aliases que se encuentran en el directorio ~/.aliases:

for file in $(ls -1 ~/.aliases/*.aliases | sort); do
	source $file
done

Además los scripts se ejecutan de forma ordenada por nombre.

Estos son los ficheros que tengo dentro de la carpeta ~/.aliases actualmente.

ls -1 .aliases/*
.aliases/android.aliases
.aliases/conda.aliases
.aliases/custom.aliases
.aliases/nvm.aliases
.aliases/sdkman.aliases
.aliases/tilix.aliases
.aliases/venv.aliases

En los siguientes apartados se muestra el contenido de los diferentes ficheros de configuración:

sdkman.aliases

#THIS MUST BE AT THE END OF THE FILE FOR SDKMAN TO WORK!!!
export SDKMAN_DIR="$HOME/.sdkman"
[[ -s "$HOME/.sdkman/bin/sdkman-init.sh" ]] && source "$HOME/.sdkman/bin/sdkman-init.sh"

conda.aliases

# added by Anaconda3 2018.12 installer
# >>> conda init >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$(CONDA_REPORT_ERRORS=false '/opt/anaconda3/bin/conda' shell.bash hook 2> /dev/null)"
if [ $? -eq 0 ]; then
    \eval "$__conda_setup"
else
    if [ -f "/opt/anaconda3/etc/profile.d/conda.sh" ]; then
        . "/opt/anaconda3/etc/profile.d/conda.sh"
        CONDA_CHANGEPS1=false conda activate base
    else
        \export PATH="/opt/anaconda3/bin:$PATH"
    fi
fi
unset __conda_setup
# <<< conda init <<<

conda deactivate

nvm.aliases

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

tilix.aliases

if [ $TILIX_ID ] || [ $VTE_VERSION ]; then
        source /etc/profile.d/vte.sh
fi

android.aliases

export PATH=$PATH:$HOME/Android/Sdk/tools:$HOME/Android/Sdk/platform-tools

venv.aliases

venv-activate() {
        if [ ! -f "$HOME/.virtualenvs/$1/bin/activate" ]; then
                echo "virtual environment '$1' doesn't exists"
                return 1
        fi
        source $HOME/.virtualenvs/$1/bin/activate
}

custom.aliases

source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh

alias src="cd $HOME/Src"
alias doc="cd $HOME/Qsync/Documents"

Almacenar las credenciales de docker registry de forma más segura

Cuando haces login en un docker registry por defecto almacena las credenciales (basic auth) en un fichero de texto sin encriptar en $HOME/.docker/config.json.

Para que no almacene las credenciales ahí y utilice el almacen del sistema (por ejemplo gnome-keyring):

Descargar una release de este proyecto:

https://github.com/docker/docker-credential-helpers/

En este momento la versión es 0.6.0 y puede ser descargada de aquí:

https://github.com/docker/docker-credential-helpers/releases/download/v0.6.0/docker-credential-secretservice-v0.6.0-amd64.tar.gz

Extraer el fichero docker-credential-secretservice y colocarlo en algún sitio en el $PATH.

Hacer logout de los registry a los que estés logado actualmente:

$ docker logout docker.registry.url

Modificar $HOME/.docker/config.json añadiendo la clave credStore con el valor secretservice.

{
  "auths": {
    "docker.registry.url": {}
  },
  "HttpHeaders": {
    "User-Agent": "Docker-Client/18.09.1 (linux)"
  },
  "credsStore": "secretservice"
}

Esto es para GNU/Linux, para el resto de sistemas ver el siguiente enlace ya que no lo he probado:

https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Desplegar docker una app Spring Boot 1.5.x desde Gradle

Utilizaremos el plugin gradle-docker para gradle.

build.gradle

plugins {
    id 'java'
    id 'org.springframework.boot' version '1.5.17.RELEASE'
    id 'com.palantir.docker' version '0.20.1'
    id 'com.palantir.docker-run' version '0.20.1'
}

...

jar {
    baseName = 'my-spring-boot-app'
    version = '1.0.0'
}

docker {
    dependsOn build
    name "my-docker-registry:5043/my-image-name"
    tags jar.version, 'latest'
    files jar.archivePath
    buildArgs(['JAR_FILE': jar.archiveName])
}

dockerRun {
    name "my-container-name"
    image "my-docker-registry:5043/my-image-name:${jar.version}"
    ports '8080:8080'
    env 'JAVA_OPTS': '-Xms128m -Xmx512m -server', 'SPRING_PROFILES_ACTIVE': 'my-spring-prifle'
    network 'my-docker-network'
    daemonize true
}

Dockerfile

FROM openjdk:8-jre-alpine
ARG JAR_FILE
COPY ${JAR_FILE} /app.jar
ENTRYPOINT exec java $JAVA_OPTS -jar /app.jar
EXPOSE 8080

Operaciones

Construir la imagen de docker

./gradlew clean docker dockerTag

REPOSITORY                              TAG     IMAGE ID            CREATED             SIZE
my-docker-registry:5043/my-image-name   latest  457475efc55d        9 minutes ago       145MB
my-docker-registry:5043/my-image-name   1.0.0   457475efc55d        9 minutes ago       145MB

Construir y ejecutar el contenedor

./gradlew dockerRun

Ver el estado del contenedor

./gradlew dockerRunStatus
> Task :dockerRunStatus
Docker container 'my-container-name' is STOPPED.

Ver el estado de la red

./gradlew dockerNetworkModeStatus
> Task :dockerNetworkModeStatus
Docker container 'my-container-name' is configured to run with 'my-docker-network' network mode.

Detener el contenedor

./gradlew dockerStop

Eliminar el contenedor

dockerRemoveContainer

Push imagen

./gradlew dockerPush

Spring Testing. Mostrar información de las peticiones

Cuando usamos MockMvc para testear controladores de Spring, es muy útil disponer del máximo de información referente a la petición realizada desde el test. Una forma muy sencilla es indicarle al «builder» que queremos que muestre en la salida del test dicha información.

import org.junit.Before;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@RunWith(MockitoJUnitRunner.class)
public abstract class MyTestClass {

    MockMvc mvc;

    @Mock
    MyRepository myRepository;

    @Before
    public void initialize() {

        mvc = MockMvcBuilders.standaloneSetup(new MyController(new MyService(myRepository)));
                .alwaysDo(print()) // Esta es la línea importante
                .build();
    }
}

Esto hace que para cada petición se se hace desde un test unitario via MockMvc muestre una información detallada de la misma:

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /my-request-path
       Parameters = {my-request-param=[my-request-param-value]}
          Headers = {my-header=[my-header-value]}

Handler:
             Type = com.example.MyController
           Method = public org.springframework.http.ResponseEntity<java.util.List<com.example.MyResponseClass>> com.example.MyController.myMethod(com.example.MyRequestBodyClass)

Async:
    Async started = false
     Async result = null

Resolved Exception:
             Type = null

ModelAndView:
        View name = null
             View = null
            Model = null

FlashMap:
       Attributes = null

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = {Content-Type=[application/json;charset=UTF-8]}
     Content type = application/json;charset=UTF-8
             Body = [{"field":"value"}]
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

Tener en cuenta que hasta versión 5.0 de Spring Framework no se muestra el contenido de la request tal y como se puede leer en el siguiente jira:

https://jira.spring.io/browse/SPR-14717