xref: /OK3568_Linux_fs/yocto/poky/bitbake/lib/bb/fetch2/ssh.py (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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