summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/bb/fetch2/ssh.py
blob: 0cbb2a6f2516255f573f3aa79502639320dbf850 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
'''
BitBake 'Fetch' implementations

This implementation is for Secure Shell (SSH), and attempts to comply with the
IETF secsh internet draft:
    http://tools.ietf.org/wg/secsh/draft-ietf-secsh-scp-sftp-ssh-uri/

    Currently does not support the sftp parameters, as this uses scp
    Also does not support the 'fingerprint' connection parameter.

    Please note that '/' is used as host, path separator not ':' as you may 
    be used to, also '~' can be used to specify user HOME, but again after '/'
    
    Example SRC_URI:
    SRC_URI = "ssh://user@host.example.com/dir/path/file.txt"
    SRC_URI = "ssh://user@host.example.com/~/file.txt"
'''

# Copyright (C) 2006  OpenedHand Ltd.
#
#
# Based in part on svk.py:
#    Copyright (C) 2006 Holger Hans Peter Freyther
#    Based on svn.py:
#        Copyright (C) 2003, 2004  Chris Larson
#        Based on functions from the base bb module:
#            Copyright 2003 Holger Schurig
#
#
# SPDX-License-Identifier: GPL-2.0-only
#

import re, os
from bb.fetch2 import check_network_access, FetchMethod, ParameterError, runfetchcmd
import urllib


__pattern__ = re.compile(r'''
 \s*                 # Skip leading whitespace
 ssh://              # scheme
 (                   # Optional username/password block
  (?P<user>\S+)      # username
  (:(?P<pass>\S+))?  # colon followed by the password (optional)
 (?P<cparam>(;[^;]+)*)?  # connection parameters block (optional)
 @
 )?
 (?P<host>\S+?)          # non-greedy match of the host
 (:(?P<port>[0-9]+))?    # colon followed by the port (optional)
 /
 (?P<path>[^;]+)         # path on the remote system, may be absolute or relative,
                         # and may include the use of '~' to reference the remote home
                         # directory
 (?P<sparam>(;[^;]+)*)?  # parameters block (optional)
 $
''', re.VERBOSE)

class SSH(FetchMethod):
    '''Class to fetch a module or modules via Secure Shell'''

    def supports(self, urldata, d):
        return __pattern__.match(urldata.url) is not None

    def supports_checksum(self, urldata):
        return False

    def urldata_init(self, urldata, d):
        if 'protocol' in urldata.parm and urldata.parm['protocol'] == 'git':
            raise ParameterError(
                "Invalid protocol - if you wish to fetch from a git " +
                "repository using ssh, you need to use " +
                "git:// prefix with protocol=ssh", urldata.url)
        m = __pattern__.match(urldata.url)
        path = m.group('path')
        path = urllib.parse.unquote(path)
        host = m.group('host')
        urldata.localpath = os.path.join(d.getVar('DL_DIR'),
                os.path.basename(os.path.normpath(path)))

    def download(self, urldata, d):
        dldir = d.getVar('DL_DIR')

        m = __pattern__.match(urldata.url)
        path = m.group('path')
        host = m.group('host')
        port = m.group('port')
        user = m.group('user')
        password = m.group('pass')

        if port:
            portarg = '-P %s' % port
        else:
            portarg = ''

        if user:
            fr = user
            if password:
                fr += ':%s' % password
            fr += '@%s' % host
        else:
            fr = host

        if path[0] != '~':
            path = '/%s' % path
        path = urllib.parse.unquote(path)

        fr += ':%s' % path

        cmd = 'scp -B -r %s %s %s/' % (
            portarg,
            fr,
            dldir
        )

        check_network_access(d, cmd, urldata.url)

        runfetchcmd(cmd, d)

    def checkstatus(self, fetch, urldata, d):
        """
        Check the status of the url
        """
        m = __pattern__.match(urldata.url)
        path = m.group('path')
        host = m.group('host')
        port = m.group('port')
        user = m.group('user')
        password = m.group('pass')

        if port:
            portarg = '-P %s' % port
        else:
            portarg = ''

        if user:
            fr = user
            if password:
                fr += ':%s' % password
            fr += '@%s' % host
        else:
            fr = host

        if path[0] != '~':
            path = '/%s' % path
        path = urllib.parse.unquote(path)

        cmd = 'ssh -o BatchMode=true %s %s [ -f %s ]' % (
            portarg,
            fr,
            path
        )

        check_network_access(d, cmd, urldata.url)
        runfetchcmd(cmd, d)

        return True