2013-03-09 12 views
38

Utilizzando i webhook di github, vorrei poter apportare modifiche a un server di sviluppo remoto. Al momento, quando nella directory appropriata, git pull ottiene eventuali modifiche che devono essere apportate. Tuttavia, non riesco a capire come chiamare quella funzione da dentro Python. Ho provato quanto segue:Come posso chiamare 'git pull' da Python?

import subprocess 
process = subprocess.Popen("git pull", stdout=subprocess.PIPE) 
output = process.communicate()[0] 

ma questo provoca il seguente errore

Traceback (most recent call last): File "", line 1, in File "/usr/lib/python2.7/subprocess.py", line 679, in init errread, errwrite) File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child raise child_exception OSError: [Errno 2] No such file or directory

C'è un modo che io possa chiamare questo comando bash dall'interno Python?

+0

Questo è un duplicato di http://stackoverflow.com/questions/4256107/running-bash-commands-in-python – ceptno

+2

@Brandon che non è vero, ci sono molte altre soluzioni, meglio ancora. – jleahy

+0

L'eseguibile 'git' nel PERCORSO? – poke

risposta

28

subprocess.Popen prevede un elenco del nome e degli argomenti del programma. Si sta passando una singola stringa, che è (con il default shell=False) equivale a:

['git pull'] 

Ciò significa che il sottoprocesso cerca di trovare un programma chiamato letteralmente git pull, e non riesce a farlo: In Python 3.3, il tuo codice solleva l'eccezione FileNotFoundError: [Errno 2] No such file or directory: 'git pull'. Invece, passare in un elenco, come questo:

import subprocess 
process = subprocess.Popen(["git", "pull"], stdout=subprocess.PIPE) 
output = process.communicate()[0] 

Tra l'altro, in Python 2.7+, è possibile semplificare questo codice con la funzione check_output convenienza:

import subprocess 
output = subprocess.check_output(["git", "pull"]) 

Inoltre, per utilizzare la funzionalità git , non è assolutamente necessario (anche se semplice e portatile) chiamare il git binario. Prendi in considerazione l'utilizzo di git-python o Dulwich.

+0

Per documentazione: * "args dovrebbe essere una sequenza di argomenti del programma ** oppure una singola stringa **." * (Enfasi mia). Ne sei sicuro, perché funziona per me? – poke

+0

@poke Sì, la documentazione è un po 'poco chiara. Se vuoi passare una stringa, devi passare in 'shell = True'. – phihag

+0

Bene, come ho detto, funziona per me facendo solo 'subprocess.Popen (" git pull ", stdout = subprocess.PIPE) .communicate()' (3.3 e 2.7 su Windows).- Beh, leggendo un po 'oltre, i documenti spiegano che questo funzionerà solo su Unix quando non passerà alcun argomento .. Nevermind then ^^ – poke

-4

Prova:

subprocess.Popen("git pull", stdout=subprocess.PIPE, shell=True) 
+2

Questo però genererebbe inutilmente una shell, vero? – phihag

+0

Vedere la risposta [sopra] (http://stackoverflow.com/a/15315617/679449) – Kermit

2

Questa è una ricetta di esempio, ho usato in uno dei miei progetti. Concordato che ci sono molti modi per farlo. :)

>>> import subprocess, shlex 
>>> git_cmd = 'git status' 
>>> kwargs = {} 
>>> kwargs['stdout'] = subprocess.PIPE 
>>> kwargs['stderr'] = subprocess.PIPE 
>>> proc = subprocess.Popen(shlex.split(git_cmd), **kwargs) 
>>> (stdout_str, stderr_str) = proc.communicate() 
>>> return_code = proc.wait() 

>>> print return_code 
0 

>>> print stdout_str 
# On branch dev 
# Untracked files: 
# (use "git add <file>..." to include in what will be committed) 
# 
# file1 
# file2 
nothing added to commit but untracked files present (use "git add" to track) 

>>> print stderr_str 

Il problema con il codice era, non eri passaggio di un array per subprocess.Popen() e quindi stava cercando di eseguire un singolo binario chiamato git pull. Invece deve eseguire il binario git con il primo argomento pull e così via.

+1

Non che 'split' debba essere davvero [' shlex.split'] (http://docs.python.org/2 /library/shlex.html#shlex.split), e quel codice è inutilmente complicato - non è necessario 'wait' dopo' communicate', e per la maggior parte dei casi d'uso, '' check_output'] (http: // docs. python.org/3/library/subprocess.html#subprocess.check_output) ha già la stringa giusta. – phihag

+0

Uso wait() per raccogliere il codice di ritorno del processo, per le mie esigenze. È facoltativo, se l'OP non è interessato al controllo del codice di ritorno. D'accordo sull'uso di 'shlex.split' però. E sì, se non sei interessato a prendere stdout o stderr puoi saltarli. Niente di male nel fornire soluzioni alternative che ti permettono di fare qualcosa di più invece degli esempi standard di documentazione di python;) – Tuxdude

+0

E come hai detto, 'check_output' è stato aggiunto solo dal 2.7, ho avuto la necessità di eseguire il mio script in ambienti con python versioni più vecchie di quella. – Tuxdude