De acordo com os documentos transfer.put () , devo ser capaz de fornecer o caminho local para um arquivo (como uma string) ou um objeto semelhante a um arquivo.
Ao usar o anterior (string), posso especificar no caminho remote
apenas o diretório de destino. Isso é usado em alguns exemplos :
c.put('myfiles.tgz', '/opt/mydata')
Mas quando tento fazer o mesmo ( c.put('file.txt', '/home/me/dir')
, sempre acabo com IOError: Failure
, porque na verdade está se comportando como se o caminho local
fosse um objeto semelhante a um arquivo e não uma string.
Ele falha especificamente em paramiko.transport.sftp.sftp._log: [chan 0] open('/home/me/dir', 'wb')
A solução é sempre fornecer o caminho completo, por exemplo
c.put('file.txt', '/home/me/dir/file.txt')
Mas isso é inconsistente com os documentos e exemplos.
Finalmente, ter que fornecer o caminho completo para $HOME
é menos que o ideal, mas parece haver um problema para isso já # 1653
Alguma atualização sobre isso? Connection.put
com remote
como string de caminho de diretório atualmente aumenta IOError
.
(Também obrigado por todo o trabalho em Fabric et al!)
Tecido 2.1.3
Paramiko 2.4.1
Invoke 1.0.0
Parece um bug legítimo, daremos uma olhada mais tarde. Patches (e testes! Uma vez que todos os nossos passam :( implicando que estamos perdendo alguns ...) bem-vindos.
Olhando para isso agora, não tenho certeza se o problema é a suposição de FLO, acho que, em vez disso, é apenas uma falta direta de implementação de munging de caminho remoto correto - em outras palavras, estamos pedindo ao servidor SFTP para abrir o diretório como um arquivo para gravar, em vez de adicionar o nome de base do arquivo local ao caminho do diretório remoto.
Log de depuração parcial do final do Fabric:
invoke.transfer.put: Massaged relative local path 'setup.py' into '/Users/jforcier/Code/oss/fabric/setup.py'
invoke.transfer.put: Uploading '/Users/jforcier/Code/oss/fabric/setup.py' to '/Users/jforcier/tmp/'
paramiko.transport.sftp.sftp._log: [chan 2] open(b'/Users/jforcier/tmp/', 'wb')
Em seguida, parte do traceback mostra que estamos lançando esse caminho de diretório em CMD_OPEN, em sftp_client.py
:
t, msg = self._request(CMD_OPEN, filename, imode, attrblock)
O que eventualmente atinge o mesmo arquivo / classe de tratamento de erro em torno do que o servidor SFTP disse que estava errado com a operação IO (que é o motivo pelo qual é apenas "Falha", porque é claro que é ... AFAIK é culpa do OpenSSH.)
De qualquer forma, é hora de escrever alguns testes para provar isso e então descobrir se é uma lógica opa (eu pensei que _estávamos_ construindo um caminho anexado em algum ponto) ou uma parte real de funcionalidade ausente.
OK, não, todo o munging gira em torno de caminhos remotos vazios ou relativos, não há verificação do diretório is.
Enquanto estou aqui, me perguntando como lidar com FLOs também, no caso em que o caminho remoto é um diretório.
Na v1, vimos o atributo .name
dos FLOs porque faz parte da API Python FLO ..._ but_ aparentemente apenas para fins de registro de depuração (em # 699). Opa. Eu examinei o código do nosso e do Paramiko e não vi nada usando isso como uma pista de "nome de arquivo".
De qualquer forma, aqui na v2 temos a oportunidade de resolver isso para reais, ou apenas lançar uma exceção explícita dizendo "uau, você precisa fornecer um caminho de arquivo remoto não-diretório para estes". Provavelmente ambos, uma vez que nem todos os FLOs necessariamente têm o atributo name de qualquer maneira.
OK, está tudo consertado, será lançado na próxima versão de correção de bugs 🎉