Mercurial > piecrust2
comparison piecrust/publishing/sftp.py @ 885:13e8b50a2113
publish: Fix publishers API and add a simple "copy" publisher.
author | Ludovic Chabant <ludovic@chabant.com> |
---|---|
date | Tue, 20 Jun 2017 21:12:35 -0700 |
parents | 3b33d9fb007c |
children | 5713b6a2850d |
comparison
equal
deleted
inserted
replaced
884:18b3e2acd069 | 885:13e8b50a2113 |
---|---|
1 import os | 1 import os |
2 import os.path | 2 import os.path |
3 import socket | |
4 import urllib.parse | 3 import urllib.parse |
5 import getpass | 4 import getpass |
6 import logging | 5 import logging |
7 import paramiko | 6 import paramiko |
8 from piecrust.publishing.base import Publisher, PublisherConfigurationError | 7 from piecrust.publishing.base import Publisher, PublisherConfigurationError |
15 PUBLISHER_NAME = 'sftp' | 14 PUBLISHER_NAME = 'sftp' |
16 PUBLISHER_SCHEME = 'sftp' | 15 PUBLISHER_SCHEME = 'sftp' |
17 | 16 |
18 def setupPublishParser(self, parser, app): | 17 def setupPublishParser(self, parser, app): |
19 parser.add_argument( | 18 parser.add_argument( |
20 '--force', | 19 '--force', |
21 action='store_true', | 20 action='store_true', |
22 help=("Upload the entire bake directory instead of only " | 21 help=("Upload the entire bake directory instead of only " |
23 "the files changed by the last bake.")) | 22 "the files changed by the last bake.")) |
23 | |
24 def parseUrlTarget(self, url): | |
25 self.config = {'host': str(url)} | |
24 | 26 |
25 def run(self, ctx): | 27 def run(self, ctx): |
26 remote = self.config | 28 host = self.config.get('host') |
27 if not self.has_url_config: | 29 if not host: |
28 host = self.getConfigValue('host') | 30 raise PublisherConfigurationError( |
29 if not host: | 31 "Publish target '%s' doesn't specify a 'host'." % |
30 raise PublisherConfigurationError( | 32 self.target) |
31 "Publish target '%s' doesn't specify a 'host'." % | 33 remote = urllib.parse.urlparse(host) |
32 self.target) | |
33 remote = urllib.parse.urlparse(host) | |
34 | 34 |
35 hostname = remote.hostname | 35 hostname = remote.hostname |
36 port = remote.port or 22 | 36 port = remote.port or 22 |
37 path = remote.path | 37 path = remote.path |
38 if not hostname: | 38 if not hostname: |
39 hostname = path | 39 hostname = path |
40 path = '' | 40 path = '' |
41 | 41 |
42 username = remote.username | 42 username = self.config.get('username', remote.username) |
43 pkey_path = None | 43 path = self.config.get('path', path) |
44 | 44 pkey_path = self.config.get('key') |
45 if not self.has_url_config: | |
46 if not username: | |
47 username = self.getConfigValue('username') | |
48 if not path: | |
49 path = self.getConfigValue('path') | |
50 | |
51 pkey_path = self.getConfigValue('key') | |
52 | 45 |
53 password = None | 46 password = None |
54 if username and not ctx.preview: | 47 if username and not ctx.preview: |
55 password = getpass.getpass("Password for '%s': " % username) | 48 password = getpass.getpass("Password for '%s': " % username) |
56 | 49 |
63 lfk = (not username and not pkey_path) | 56 lfk = (not username and not pkey_path) |
64 sshc = paramiko.SSHClient() | 57 sshc = paramiko.SSHClient() |
65 sshc.load_system_host_keys() | 58 sshc.load_system_host_keys() |
66 sshc.set_missing_host_key_policy(paramiko.WarningPolicy()) | 59 sshc.set_missing_host_key_policy(paramiko.WarningPolicy()) |
67 sshc.connect( | 60 sshc.connect( |
68 hostname, port=port, | 61 hostname, port=port, |
69 username=username, password=password, | 62 username=username, password=password, |
70 key_filename=pkey_path, | 63 key_filename=pkey_path, |
71 look_for_keys=lfk) | 64 look_for_keys=lfk) |
72 try: | 65 try: |
73 logger.info("Connected as %s" % | 66 logger.info("Connected as %s" % |
74 sshc.get_transport().get_username()) | 67 sshc.get_transport().get_username()) |
75 client = sshc.open_sftp() | 68 client = sshc.open_sftp() |
76 try: | 69 try: |
118 try: | 111 try: |
119 client.remove(rel_path) | 112 client.remove(rel_path) |
120 except OSError: | 113 except OSError: |
121 pass | 114 pass |
122 else: | 115 else: |
123 logger.info("Nothing to upload or delete on the remote server.") | 116 logger.info( |
124 logger.info("If you want to force uploading the entire website, " | 117 "Nothing to upload or delete on the remote server.") |
125 "use the `--force` flag.") | 118 logger.info( |
119 "If you want to force uploading the entire website, " | |
120 "use the `--force` flag.") | |
126 else: | 121 else: |
127 logger.info("Uploading entire website...") | 122 logger.info("Uploading entire website...") |
128 for dirpath, dirnames, filenames in os.walk(ctx.bake_out_dir): | 123 for dirpath, dirnames, filenames in os.walk(ctx.bake_out_dir): |
129 for f in filenames: | 124 for f in filenames: |
130 abs_f = os.path.join(dirpath, f) | 125 abs_f = os.path.join(dirpath, f) |
146 cur = '' | 141 cur = '' |
147 for b in remote_bits[:-1]: | 142 for b in remote_bits[:-1]: |
148 cur = os.path.join(cur, b) | 143 cur = os.path.join(cur, b) |
149 if cur not in known_dirs: | 144 if cur not in known_dirs: |
150 try: | 145 try: |
151 info = client.stat(cur) | 146 client.stat(cur) |
152 except FileNotFoundError: | 147 except FileNotFoundError: |
153 logger.debug("Creating remote dir: %s" % cur) | 148 logger.debug("Creating remote dir: %s" % cur) |
154 client.mkdir(cur) | 149 client.mkdir(cur) |
155 known_dirs[cur] = True | 150 known_dirs[cur] = True |
156 | 151 |