2010-07-19 12 views
8

È possibile rendere autonomo il file fabfile?
Non mi piace molto eseguire lo strumento esterno 'fab'. Se riesco a ottenere lo standalone fabfile posso eseguire il file dall'interno (Eclipse/Pydev) IDE, facilmente eseguire il debug, configurazioni uso di progetto e di percorsi, ecc
Perché non questo lavoro:Fabfile stand-alone per tessuto?

from fabric.api import run 

def host_type(): 
    run('uname -s') 

if __name__ == '__main__': 
    host_type()  

risposta

13

Alla fine ho trovato la soluzione (ed è davvero semplice!).
Nel mio fabfile, ho aggiunto:

from fabric.main import main 

if __name__ == '__main__': 
    import sys 
    sys.argv = ['fab', '-f', __file__, 'update_server'] 
    main() 

Spero che questo aiuta le persone ...

+0

Questo genera un sottoprocesso come la soluzione di muksie? Il motivo principale per cui ho esplorato questo problema è che i sottoprocessi extra sono qualcosa che vogliamo eliminare. –

+1

Se modifichi il tuo compito sys.argv, funzionerà con qualsiasi gruppo di comandi. sys.argv [0] è già il nome dello script, quindi: sys.argv = ['fab', '-f'] + sys.argv – mqsoh

+0

Funziona fintanto che il file ha estensione '.py'. Non ho ancora trovato il modo di farlo funzionare per qualsiasi estensione. – Wernight

2

Questo non è davvero un bel soluzione, ma funziona:

import subprocess 

def hello(): 
    print 'Hello' 

if __name__ == '__main__': 
    subprocess.call(['fab', '-f', __file__, 'hello']) 
+0

Sì, non proprio bello (ma molto originale +1!). Inoltre, non affronta stdio (ad esempio prompt interattivo per password (che presumo sia risolvibile)). –

+0

Dirottando il commento principale per dire che nelle ultime versioni di fabric è possibile utilizzare il comando 'execute' invece di' subprocess.call' http://fabric.readthedocs.org/en/1.4.3/usage/execution.html# eseguire . – tutuca

3

Se ricordo bene, non ho potuto ottenere l'API del tessuto per fare quello che volevo neanche. Ho deciso di abbandonare l'ulteriore livello del tutto e utilizzare Paramiko (la libreria SSH sottostante utilizzato per Tessuto) direttamente:

import os 
import paramiko 

ssh = paramiko.SSHClient() 
ssh.load_system_host_keys() 
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
ssh.connect('hostname.example.com', 22, 'username', 'password') 
ssh.save_host_keys(os.path.expanduser('~/.ssh/known_hosts')) 
stdin, stdout, stderr = ssh.exec_command('uname -s') 
print stdout.read() 

Mentre ci sono un paio di passi coinvolti, facendo in questo modo consente di sfruttare direttamente lo strato di SSH , invece di usare subprocess per spanare un'altra istanza Python, o capire l'API Fabric. Ho diversi progetti, sia web che console, che usano Paramiko in questo modo e non ho avuto troppi problemi.

Paramiko è extensively documented.

+0

Purtroppo, questa è la migliore risposta per me. Grazie! –

2

ho messo a punto l'esempio precedente al passato attraverso argomenti argv si potrebbe desiderare di passare ai comandi locali e specificare un lista predefinita_commandi opzionale invece di un nome comando codificato in modo rigido. Nota, il nome del file deve avere l'estensione .py o fab non lo rileverà come file favoloso!

#!/usr/bin/env python 
from fabric.api import local 

default_commands = ['hello', ] 

def hello(): 
    print ('hello world') 

def hostname(): 
    local('hostname') 

if __name__ == '__main__': 
    import sys 
    from fabric.main import main 
    sys.argv = ['fab', '-f', __file__,] + default_commands + sys.argv[1:] 
    main() 
2

docs.fabfile.org/en/1.4.0/usage/library.html

"Come quella sezione menziona, la chiave è semplicemente quella corsa, sudo e gli altri operazioni di guardare solo in un posto per la connessione: env.host_string. Tutti gli gli altri meccanismi per l'impostazione degli host sono interpretati dallo strumento fab quando viene eseguito e non hanno importanza quando vengono eseguiti come libreria. "

Stavo osservando lo stesso problema quando ho trovato questo. Inoltre, mentre guardo ricordo che menziono che, se usato in un file favoloso, i cambiamenti di env non dovrebbero essere nella stessa def di run, sudo. Chissà se questo si applica ancora quando usato in modalità "libreria".

EDIT: Ecco un esempio di implementazione detto

from fabric.api import env, run 

def main(): 
    run("uname -a") 

def setup(): 
    env.host_string = "[email protected]" 

if __name__ == '__main__': 
    setup() 
    main() 
2
# thanks to aaron, extending his code a little more 
# here is a little bit more of a graceful solution than running subprocess.call, and specifying multiple hosts 

from fabric.api import env, run 

def main(): 
    run("uname -a") 

def setup(): 
    env.hosts = ['host0','host1'] 

if __name__ == '__main__': 
    setup() 
    for host in env.hosts: 
     env.host_string = host 
     main() 
1

Aggiungi questo al fine del file fab.

if __name__ == '__main__': 
    from fabric.main import main 
    import sys 

    sys.argv = ['fab', '-f', __file__] + sys.argv[1:] 

    main() 
2

Dal 1.5.0 non c'è modo un modo migliore per farlo che fare in giro con argv.

import fabric.main 

def main(): 
    fabric.main.main(fabfile_locations=[__file__]) 

if __name__ == "__main__": 
    main() 

questo può anche essere utilizzato come uno script console in setup.py

0

Questa è la mia versione modificata di Greg's answer che cambia comportamento predefinito per mostrare i comandi disponibili invece di elencare le tonnellate di opzioni di tessuto.

if __name__ == '__main__': 
    # imports for standalone mode only 
    import sys, fabric.main 

    # show available commands by default 
    if not sys.argv[1:]: 
     sys.argv.append('--list') 

    fabric.main.main(fabfile_locations=[__file__])