comandi di shell in bash o python? Quanto incapsulamento è troppo?

5

Sto pensando a come decidere se è meglio incapsulare il mio lavoro dietro nomi di funzioni ben definiti, o esporlo - cosa che aiuterà gli sviluppatori a capire cosa sta succedendo più velocemente? Esiste un nome per lo studio di questo tipo di problema?

In particolare, se eseguo un gruppo di comandi bash alla fine, ma ho una logica significativamente complessa attorno a quei comandi, a che punto ha senso scrivere in un linguaggio di alto livello come Python, anche se questo offusca gli attuali comandi bash eseguiti?

Problema dettagliato

Attualmente sto provando a scrivere uno script di build Jenkins per il mio progetto con circa i seguenti passaggi:

  • Estrai il mio codice da github
  • Compilare file sass in CSS
  • Apri una sottocartella da un altro progetto github
  • Comprimi il progetto
  • Caricalo in un archivio oggetti con un ID univoco

Sto pensando a come scrivere per essere il più semplice possibile per gli sviluppatori futuri (questo codice non verrà mai visto dagli utenti finali). Probabilmente questi sviluppatori, ma non sicuramente, saranno abbastanza bravi in Python. Avranno sicuramente una familiarità passeggera con la linea di comando, ma probabilmente non conosceranno lo script di bash più complesso.

La prima iterazione di questo script di build era solo una lista di comandi sequenziali, qualcosa del tipo:

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

Tuttavia, questo insieme di comandi è diventato rapidamente più complesso quando ho iniziato a fare cose come clonare il progetto git se non era già lì, altrimenti aggiornarlo - per accelerare la compilazione. Prima che me ne accorgessi, avevo 50 linee e un paio di condizioni condizionali.

Quindi la prima cosa che ho fatto è stata incapsulare queste in funzioni bash, ad es. update_git_dir , quindi il mio script di build è più simile a questo:

#!/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

Questo è un livello di incapsulamento. Ora lo sviluppatore, che avrebbe compreso direttamente i comandi git clone etc., non può effettivamente vedere cosa sta succedendo. Devono cercare in helper_functions.sh .

Tuttavia, col passare del tempo mi sono reso conto che molte delle mie funzioni di supporto ora consistevano in più istruzioni condizionali, assegnazioni di variabili e chiamate di funzioni rispetto ai comandi effettivi. Queste dichiarazioni condizionali possono essere piuttosto opache per qualcuno che non ha familiarità con lo scripting 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})

    ...

Così ho iniziato a migrare il mio codice in Python. Così ora il mio script di build assomiglia a questo:

#!/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

Ora, quando guardi in builders.py , è molto più semplice comprendere la logica: le istruzioni% do% di call e le chiamate di funzione sono molto più leggibili, ma ora siamo ancora più lontani dai comandi della shell reale. Nel mio codice Python il modo più simile a cui riesco ad eseguire direttamente i comandi della shell è il seguente:

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 lo sviluppatore ha bisogno di capire esattamente quali comandi vengono eseguiti, ora è molto più difficile.

Riepilogo

Quindi, come posso decidere qual è la migliore architettura per massimizzare la trasparenza mentre incapsula la complessità?

Questo problema sembra simile a quando lavoro con l'iniezione delle dipendenze, dove più dipendenze iniettio piuttosto che incapsulato, più il mio codice di inizializzazione diventa complesso e ho un problema simile a disegnare la linea.

Esiste un nome per questo campo di studi?

    
posta Robin Winslow 04.09.2015 - 16:19
fonte

4 risposte

2

Darei un xonsh , un mix intelligente di 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.

Approfitta dell'astrazione e del sistema dei pacchetti di Python (3), abbinato a delle buone condizioni, ma scrivi ciò che deve essere nella shell come solo shell.

per es.,

#!/usr/bin/env xonsh

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

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

Si noti che solo un po 'di bruttezza $() è richiesto per la shell in-line all'interno di python, e funziona semplicemente (TM) se si suddividono le cose chiaramente per linea (es. le righe di istruzione if )

Molti altri dettagli (incluso l'incorporamento di python nelle linee di shell con @() ) nel tutorial link

Tu puoi usarlo come shell di sistema. Ma solo perché puoi non significa che dovrebbe : -)

    
risposta data 04.09.2015 - 16:38
fonte
1

Non fornirò una risposta sì / no immediata, ma alcuni pensieri sulla situazione.

Costruire script poiché molte persone dipendono da loro dovrebbe essere l'area del codice più facile da capire. Direi che un lungo "noioso" bash non dovrebbe essere un problema purché sia facilmente comprensibile. Vorrei aggiungere un suggerimento alla "configurazione & & & & & installa l'installazione" della C in vari uffici.

Lo script di bash sembra eseguire l'inizializzazione delle variabili e l'assegnazione dei valori predefiniti, nessuno di questi entrerebbe in una struttura if-then-else profonda.

Una stima della dimensione degli script di bash (anche se è sicuramente discutibile) è che se è più di 100 righe di codice di quanto potrebbe aver bisogno di essere scritto in un programma "corretto". Anche se la frase precedente è una questione di opinione.

Se decidi di non seguire la rotta bash, allora devi entrare in strumenti di costruzione creati appositamente per questo scopo. Ant / Maven / Gradle nel mondo Java e molti altri per piattaforme diverse. Riesco a vedere il tuo esempio come una serie di obiettivi di compilazione per alcuni strumenti che ho usato in passato, come una sequenza di Rake attività o bazel .

Suppongo che se segui questa strada, dovrebbe essere uno nella lingua più utilizzata del progetto, se possibile (più facile da mantenere).

Non so se c'è un nome per il campo, ma qualcuno che fa questo giorno per giorno è chiamato "ingegnere dell'integrazione" in alcune aziende.

    
risposta data 04.09.2015 - 16:36
fonte
1

Se fossi nella tua posizione, userei link È fondamentalmente Rake per Python.

    
risposta data 04.09.2015 - 20:16
fonte
0

Piuttosto che preoccuparsi di quanta astrazione è troppo per uno strumento di costruzione / integrazione, optate invece per uno strumento comunemente usato dagli sviluppatori Python per fare questo genere di cose. Otterrai molto più utilizzo di uno strumento di costruzione ben noto, ma molto astratto di quello che farai con lo strumento di creazione più semplice, scritto e semplice che faccia la stessa cosa.

Che cosa è più importante da capire: Conoscendo i grossi dettagli su come viene creato un file gzip in Bash, o che questi file sono compressi con gzip e tutte le maniere di caos e panico si verificano se viene omesso?

Consiglierei di cercare gli strumenti di sviluppo Python. Chiedi alla comunità python cosa consigliano e scegli un progetto open source. Probabilmente ha più funzioni di quelle che hai creato e probabilmente è stato testato più completamente.

    
risposta data 04.09.2015 - 20:02
fonte

Leggi altre domande sui tag