Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow copying files from remote host(s) to local host #47

Closed
wants to merge 14 commits into from

Conversation

Caid11
Copy link
Contributor

@Caid11 Caid11 commented Nov 5, 2015

Adds support for copying files from remote hosts to local host as described in #40.

A new method, copy_file_to_local, has been added to both pssh_client and ssh_client. In ssh_client, its logic is pretty similar to copy_file, but was different enough that I figured it would be better to create a new method rather than make copy_file more complex. In pssh_client, the logic is almost identical between copy_file and copy_file_to_local; the method was duplicated to maintain the pattern between ssh_client and pssh_client.

While I think keeping copy_file simple and creating a new method is better, I also see the benefit of using one method to perform both functions, and am completely open to rolling the two functions together.

Filenames are de-duplicated by appending an underscore followed by the hostname when using pssh_client to copy files to the local host.

if local_file.startswith(os.path.sep):
destination = os.path.sep + destination
if not os.path.exists(destination):
os.mkdir(destination)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

os.mkdir is not recursive and will fail if parent path(s) do not exist.

Suggest os.makedirs is used instead.

Also needs exception handling.

@pkittenis
Copy link
Member

Many thanks for picking up another feature enhancement :)

Comments in line.

@Caid11
Copy link
Contributor Author

Caid11 commented Nov 5, 2015

No problem! Thanks for your patience and feedback as I take this on.

password=self.password,
port=self.port, pkey=self.pkey,
forward_ssh_agent=self.forward_ssh_agent)
return self.host_clients[host].copy_file_to_local(remote_file, local_file + '_' + host)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though there is little performance gained by it in this case, given the small memory footprint of the variables, this is better written as '_'.join([local_file, host])

For very large host lists, it can make a pretty big difference.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't realize using + to concatenate strings did that. I'll switch it to join.

try:
os.makedirs(destination)
except OSError, exception:
logger.error("Unable to create local directory structure.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be good to log the directory the error occurred in - OSError exception does not include that info.

Also, to re-raise the exception that was caught in a try:, can just use raise by itself within the try block. No need to hold the exception variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the tip! Will get that fixed.

@pkittenis
Copy link
Member

Out of interest, are you set on the copy_file_to_local name?

I agree the remote copy behaviour should be in separate function - they are two separate features.

Would favour a name such as copy_remote_file though.

In my view it's more concise and clearer to the casual reader what copy_file and copy_remote_file do, especially given the context the arguments give. copy_file takes local and remote paths, to and from, copy remote file takes remote and local paths, to and from.

Prepared to be convinced otherwise though :)

for host in self.hosts]

def _copy_file_to_local(self, host, remote_file, local_file):
"""Make sftp client, copy file to local"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This docstring is not valid for this function, should be in the SSHClient equivalent function.

NB - docstrings for internal functions (ones that start with _) are completely optional as they will not appear in the documentation, only in, say, ipython interactive documentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the note on internal vs. external docstrings, I didn't realize the internal ones wouldn't show up in the docs.

I am a little confused on why the docstring is invalid, however. I attempted to just change the docstring for copy_file from pssh_client to reflect copy_file_to_local. Are you saying I should put it in ssh_client instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's right - the 'make sftp client' bit of the docstring applies to SSHClient._copy_file but not ParallelSSHClient._copy_file.

That said, not that important since they are both internal functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see. Thanks for clearing that up for me.

@Caid11
Copy link
Contributor Author

Caid11 commented Nov 6, 2015

I initially thought about going with copy_remote_file, but decided not to because both functions involve remote files, just in different ways. However, I didn't think about how the arguments give the name more context. With that in mind, I agree that copy_remote_file would be a better name.

@Caid11
Copy link
Contributor Author

Caid11 commented Nov 18, 2015

Just a heads up @pkittenis, this PR isn't dead, I've just been a little too busy to work on it the last little while.

@pkittenis
Copy link
Member

No worries, thanks for the heads up

@pkittenis
Copy link
Member

Pro tip for when you get a chance - if you add the email address used in the commits that you have made to your github account, your username will show up as contributor in this project 👍

Contributions, yours and others, are much appreciated and there should be recognition of them :)

@Caid11
Copy link
Contributor Author

Caid11 commented Dec 3, 2015

Wow, I had no idea. Thanks! Also, thanks for your patience while I've let this sit. I've got finals in just a couple of weeks, then I'll be able to get this finished and hopefully make some more contributions.

@Caid11
Copy link
Contributor Author

Caid11 commented Dec 23, 2015

Think I've gotten this to a good point. Can't figure out to force os.mkdir to fail, though, so I'm having some trouble writing that test.

@pkittenis
Copy link
Member

Cool, thank you, I'll have a look at it soon.

@pkittenis
Copy link
Member

Re-raised at #58 with upstream changes.

@pkittenis pkittenis closed this May 3, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants