views:

1030

answers:

2

Hello,

I am trying to do a CVS login from Python by calling the cvs.exe process. When calling cvs.exe by hand, it prints a message to the console and then waits for the user to input the password.

When calling it with subprocess.Popen, I've noticed that the call blocks. The code is

subprocess.Popen(cvscmd, shell = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE,
    stderr = subprocess.PIPE)

I assume that it blocks because it's waiting for input, but my expectation was that calling Popen would return immediately and then I could call subprocess.communicate() to input the actual password. How can I achieve this behaviour and avoid blocking on Popen?

OS: Windows XP
Python: 2.6
cvs.exe: 1.11

+1  A: 
  • Remove the shell=True part. Your shell has nothing to do with it. Using shell=True is a common cause of trouble.
  • Use a list of parameters for cmd.

Example:

cmd = ['cvs', 
       '-d:pserver:[email protected]:/cvsroot/bayonne', 
       'login']
p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)

This won't block on my system (my script continues executing). However since cvs reads the password directly from the terminal (not from standard input or output) you can't just write the password to the subprocess' stdin.

What you could do is pass the password as part of the CVSROOT specification instead, like this:

:pserver:<user>[:<passwd>]@<server>:/<path>

I.e. a function to login to a sourceforge project:

import subprocess

def login_to_sourceforge_cvs(project, username='anonymous', password=''):
    host = '%s.cvs.sourceforge.net' % project
    path = '/cvsroot/%s' % project
    cmd = ['cvs', 
           '-d:pserver:%s:%s@%s:%s' % (username, password, host, path), 
           'login']
    p = subprocess.Popen(cmd, stdin=subprocess.PIPE, 
                              stdout=subprocess.PIPE
                              stderr=subprocess.STDOUT) 
    return p

This works for me. Calling

login_to_sourceforge_cvs('bayonne')

Will log in anonymously to the bayonne project's cvs.

nosklo
Password as part of CVSROOT seems like a better idea, but passing the password makes cvs.exe think that the username is actually "user:password"!e.g: typing cvs -d :pserver:user:pass@server:path at the command line tries to do a log in for "user:pass" and it's still asking for a password
rpg
@Razvan: My version of CVS seems to work as I said. Maybe you have a modified version? Where did you get your cvs from? Can you upgrade? Have you tried my example code?
nosklo
nosklo, I tried removing shell=True and passing the command line as a list, but that didn't work because of the cvs.exe behaviour. I took your advice and redownloaded cvs.exe from ftp.gnu.org, because the binary I had was downloaded from another site. It worked! Thanks for your help.
rpg
A: 

If you are automating external programs that need input - like password - your best bet would probably be to use pexpect.

Heikki Toivonen