Comandos do shell no bash ou python? Quanto encapsulamento é demais?

5

Estou pensando em como decidir se é melhor encapsular meu trabalho por trás de nomes de funções bem nomeados ou expor isso - o que ajudará os desenvolvedores a entender o que está acontecendo mais rapidamente? Existe um nome para o estudo deste tipo de problema?

Especificamente, se eu estou executando um monte de comandos bash, em última análise, mas eu tenho lógica significativamente complexa em torno desses comandos, em que ponto faz sentido para escrever isso em uma linguagem de alto nível como o Python, mesmo que isso ofusque os comandos reais do bash sendo executados?

Problema detalhado

Atualmente, estou tentando escrever um script de criação do Jenkins para meu projeto com aproximadamente as seguintes etapas:

  • Puxar meu código do github
  • Compilar arquivos sass em CSS
  • Baixar uma subpasta de um projeto diferente do github
  • Compacte o projeto
  • Faça o upload para um repositório de objetos com um ID exclusivo

Estou pensando em como escrever isso para ser o mais fácil possível para futuros desenvolvedores (esse código nunca será visto pelos usuários finais). Esses desenvolvedores provavelmente serão bons, mas não definitivamente, no Python. Eles definitivamente terão uma familiaridade passageira com a linha de comando, mas provavelmente não estarão familiarizados com scripts de bash mais complexos.

A primeira iteração deste script de construção foi apenas uma lista de comandos sequenciais, algo como:

git clone [email protected]:username/project.git
git clone [email protected]:username/sub-project.git project/sub-project
sass --update project/css
tar -czf project.tgz project
swift upload my-container project.tgz --object-name=project-'sha1sum project.tgz'.tgz

No entanto, esse conjunto de comandos rapidamente se tornou mais complexo quando comecei a fazer coisas como clonar apenas o projeto git se ele já não estivesse lá, senão atualizá-lo - para acelerar a compilação. Antes que eu percebesse, eu tinha 50 linhas e alguns condicionais.

Então, a primeira coisa que fiz foi encapsular essas funções no bash, por exemplo, update_git_dir , então meu script de construção se parece mais com isso:

#!/usr/bin/env bash

source helper_functions.sh

update_git_dir project [email protected]:username/project.git
build_sass project/css
create_archive project project.tgz
upload_to_swift project.tgz

Este é um nível de encapsulamento. Agora, o desenvolvedor, que teria entendido os comandos git clone etc. diretamente, não pode realmente ver o que está acontecendo. Eles precisam procurar em helper_functions.sh .

No entanto, com o passar do tempo, percebi que muitas das minhas funções auxiliares consistiam agora em mais instruções condicionais, atribuições de variáveis e chamadas de funções do que comandos reais. Estas declarações condicionais podem ser bastante opacas para alguém que não esteja familiarizado com o script bash:

function create_archive {
    project_name=${1}
    archive_filename=${2}

    # Get revision ids
    dependencies_requirements_revision=$(cat ${project_name}/sub-project/requirements-revision.txt)

    requirements_context=${project_name}/${requirements_file}
    requirements_dir=$(dirname ${requirements_context})
    if [ "${requirements_dir}" != "${project_name}" ]; then
        requirements_context=${requirements_dir}
    fi
    latest_revision=$(git-revision-hash ${project_name})

    ...

Então comecei a migrar meu código para o Python. Então agora meu script de construção é assim:

#!/usr/bin/env python

from builders import GitProjectBuilder

builder = GitProjectBuilder(
    project_name='my-project',
    swift_container='my-container',
    git_repository='[email protected]:username/project.git',
    sub_project='[email protected]:username/sub-project.git'
)

# Compress and upload
builder.build_sass(directory='css')
builder.get_sub_project(repo='[email protected]:username/sub-project.git')
builder.build_archive(name='archive.tgz')
upload_location = builder.upload_archive_to_swift(archive='archive.tgz')
print upload_location

Agora, quando você olha em builders.py , é muito mais fácil entender a lógica - if declarações e chamadas de função são muito mais legíveis - mas agora estamos ainda mais longe dos comandos reais do shell. No meu código python, o mais próximo que eu chego de executar diretamente os comandos shell é o seguinte:

def build_archive(self, archive):
    print subprocess.check_output(
        (
            'tar --exclude-vcs --create --file '
            '{archive_filename}.tar {project_dir}'
        ).format(
            archive_filename=archive_filename,
            project_dir=self.project_name
        ).split()
    )

Se o desenvolvedor precisa descobrir exatamente quais comandos estão sendo executados, agora é muito mais difícil.

Resumir

Então, como decido qual é a melhor arquitetura para maximizar a transparência ao encapsular a complexidade?

Esse problema parece ser semelhante a quando estou trabalhando com injeção de dependência, onde quanto mais dependências eu injetar em vez de encapsular, mais complexo fica meu código de inicialização - e eu tenho um problema parecido na linha.

Existe um nome para este campo de estudo?

    
por Robin Winslow 04.09.2015 / 16:19
fonte

4 respostas

2

Eu daria xonsh , é uma combinação inteligente de shell e python.

xonsh is a Python-ish, BASHwards-compatible shell language and command prompt. The language is a superset of Python 3.4 with additional shell primitives that you are used to from BASH and IPython. xonsh is meant for the daily use of experts and novices alike.

Aproveite o sistema de abstração e pacote do Python (3), juntamente com boas condicionais, mas escreva o que precisa estar no shell como apenas shell.

por exemplo,

#!/usr/bin/env xonsh

def exists(filename):
    return filename in $(ls)

if exists(".git"):
    git checkout master
    git pull
else:
    git clone $GITURL

Observe que apenas um pouco de feiura $() é necessário para o shell in-line dentro do python e Just Works (TM) se você estiver dividindo as coisas claramente por linha (por exemplo, as linhas da instrução if )

Mais detalhes (incluindo incorporação de python em linhas de shell com @() ) no tutorial link

Você pode usá-lo como seu shell do sistema. Mas só porque você pode não significa que você deveria : -)

    
por 04.09.2015 / 16:38
fonte
1

Não fornecerei uma resposta imediata de sim / não, mas algumas reflexões sobre a situação.

Construa scripts já que muitas pessoas dependem deles deve ser a área mais fácil de entender do seu código. Eu diria que uma longa e chata festança não deve ser um problema, desde que seja facilmente compreendida. Eu adicionaria uma sugestão para o "configure & build & build & build install" do C em vários unices.

Seu script bash parece estar fazendo inicialização de variável e atribuição de padrões, nenhum deles entraria em uma estrutura deep if-then-else.

Uma estimativa do tamanho dos scripts bash (embora certamente seja discutível) é que, se forem mais de 100 linhas de código, talvez precisem ser gravadas em um programa "adequado". Embora a frase anterior seja uma questão de opinião.

Se você decidir não percorrer a rota bash, então você precisa entrar em ferramentas de construção que são feitas apenas para esse propósito. Ant / Maven / Gradle no mundo de Java e muitos outros para diferentes plataformas. Eu posso ver seu exemplo como uma série de metas de construção para algumas ferramentas que usei no passado, como uma sequência de Rake tarefas ou bazel queridos.

Eu suponho que se você for por esse caminho, então deve ser um dos idiomas mais usados do projeto, se possível (mais fácil de manter).

Eu não sei se existe um nome para o campo, mas alguém fazendo isso no dia a dia é chamado de "engenheiro de integração" em algumas empresas.

    
por 04.09.2015 / 16:36
fonte
1

Se eu estivesse na sua posição, usaria o link É basicamente o Rake para python.

    
por 04.09.2015 / 20:16
fonte
0

Em vez de se preocupar com o quanto a abstração é demais para uma ferramenta de construção / integração, opte por uma ferramenta comumente usada pelos desenvolvedores do Python para fazer esse tipo de coisa. Você obterá muito mais uso de uma ferramenta de construção bem conhecida, mas altamente abstrata, do que a mais clara e simples ferramenta de criação que faz a mesma coisa.

O que é mais importante entender: Conhecendo os detalhes sobre como um arquivo gzip é criado no Bash, ou que esses arquivos são compactados juntos e todas as maneiras de caos e pânico ocorrerão se ele for omitido?

Eu recomendaria pesquisar por ferramentas de compilação do Python. Pergunte à comunidade python o que eles recomendam e escolha um projeto de código aberto. Provavelmente tem mais recursos do que você construiu e provavelmente foi testado mais completamente.

    
por 04.09.2015 / 20:02
fonte