1''' 2BitBake 'Fetch' implementations 3 4This implementation is for Secure Shell (SSH), and attempts to comply with the 5IETF secsh internet draft: 6 http://tools.ietf.org/wg/secsh/draft-ietf-secsh-scp-sftp-ssh-uri/ 7 8 Currently does not support the sftp parameters, as this uses scp 9 Also does not support the 'fingerprint' connection parameter. 10 11 Please note that '/' is used as host, path separator not ':' as you may 12 be used to, also '~' can be used to specify user HOME, but again after '/' 13 14 Example SRC_URI: 15 SRC_URI = "ssh://user@host.example.com/dir/path/file.txt" 16 SRC_URI = "ssh://user@host.example.com/~/file.txt" 17''' 18 19# Copyright (C) 2006 OpenedHand Ltd. 20# 21# 22# Based in part on svk.py: 23# Copyright (C) 2006 Holger Hans Peter Freyther 24# Based on svn.py: 25# Copyright (C) 2003, 2004 Chris Larson 26# Based on functions from the base bb module: 27# Copyright 2003 Holger Schurig 28# 29# 30# SPDX-License-Identifier: GPL-2.0-only 31# 32 33import re, os 34from bb.fetch2 import check_network_access, FetchMethod, ParameterError, runfetchcmd 35import urllib 36 37 38__pattern__ = re.compile(r''' 39 \s* # Skip leading whitespace 40 ssh:// # scheme 41 ( # Optional username/password block 42 (?P<user>\S+) # username 43 (:(?P<pass>\S+))? # colon followed by the password (optional) 44 (?P<cparam>(;[^;]+)*)? # connection parameters block (optional) 45 @ 46 )? 47 (?P<host>\S+?) # non-greedy match of the host 48 (:(?P<port>[0-9]+))? # colon followed by the port (optional) 49 / 50 (?P<path>[^;]+) # path on the remote system, may be absolute or relative, 51 # and may include the use of '~' to reference the remote home 52 # directory 53 (?P<sparam>(;[^;]+)*)? # parameters block (optional) 54 $ 55''', re.VERBOSE) 56 57class SSH(FetchMethod): 58 '''Class to fetch a module or modules via Secure Shell''' 59 60 def supports(self, urldata, d): 61 return __pattern__.match(urldata.url) is not None 62 63 def supports_checksum(self, urldata): 64 return False 65 66 def urldata_init(self, urldata, d): 67 if 'protocol' in urldata.parm and urldata.parm['protocol'] == 'git': 68 raise ParameterError( 69 "Invalid protocol - if you wish to fetch from a git " + 70 "repository using ssh, you need to use " + 71 "git:// prefix with protocol=ssh", urldata.url) 72 m = __pattern__.match(urldata.url) 73 path = m.group('path') 74 path = urllib.parse.unquote(path) 75 host = m.group('host') 76 urldata.localpath = os.path.join(d.getVar('DL_DIR'), 77 os.path.basename(os.path.normpath(path))) 78 79 def download(self, urldata, d): 80 dldir = d.getVar('DL_DIR') 81 82 m = __pattern__.match(urldata.url) 83 path = m.group('path') 84 host = m.group('host') 85 port = m.group('port') 86 user = m.group('user') 87 password = m.group('pass') 88 89 if port: 90 portarg = '-P %s' % port 91 else: 92 portarg = '' 93 94 if user: 95 fr = user 96 if password: 97 fr += ':%s' % password 98 fr += '@%s' % host 99 else: 100 fr = host 101 102 if path[0] != '~': 103 path = '/%s' % path 104 path = urllib.parse.unquote(path) 105 106 fr += ':%s' % path 107 108 cmd = 'scp -B -r %s %s %s/' % ( 109 portarg, 110 fr, 111 dldir 112 ) 113 114 check_network_access(d, cmd, urldata.url) 115 116 runfetchcmd(cmd, d) 117 118 def checkstatus(self, fetch, urldata, d): 119 """ 120 Check the status of the url 121 """ 122 m = __pattern__.match(urldata.url) 123 path = m.group('path') 124 host = m.group('host') 125 port = m.group('port') 126 user = m.group('user') 127 password = m.group('pass') 128 129 if port: 130 portarg = '-P %s' % port 131 else: 132 portarg = '' 133 134 if user: 135 fr = user 136 if password: 137 fr += ':%s' % password 138 fr += '@%s' % host 139 else: 140 fr = host 141 142 if path[0] != '~': 143 path = '/%s' % path 144 path = urllib.parse.unquote(path) 145 146 cmd = 'ssh -o BatchMode=true %s %s [ -f %s ]' % ( 147 portarg, 148 fr, 149 path 150 ) 151 152 check_network_access(d, cmd, urldata.url) 153 154 if runfetchcmd(cmd, d): 155 return True 156 157 return False 158