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