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