Add ssh fetcher written by kergoth (from poky)
[bitbake.git] / lib / bb / fetch / ssh.py
1 #!/usr/bin/env python
2 # ex:ts=4:sw=4:sts=4:et
3 # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4 '''
5 BitBake 'Fetch' implementations
6
7 This implementation is for Secure Shell (SSH), and attempts to comply with the
8 IETF secsh internet draft:
9     http://tools.ietf.org/wg/secsh/draft-ietf-secsh-scp-sftp-ssh-uri/
10
11     Currently does not support the sftp parameters, as this uses scp
12     Also does not support the 'fingerprint' connection parameter.
13
14 Copyright (C) 2006  OpenedHand Ltd.
15
16 Based in part on svk.py:
17     Copyright (C) 2006 Holger Hans Peter Freyther
18     Based on svn.py:
19         Copyright (C) 2003, 2004  Chris Larson
20         Based on functions from the base bb module:
21             Copyright 2003 Holger Schurig
22
23
24 This program is free software; you can redistribute it and/or modify it under
25 the terms of the GNU General Public License as published by the Free Software
26 Foundation; either version 2 of the License, or (at your option) any later
27 version.
28
29 This program is distributed in the hope that it will be useful, but WITHOUT
30 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
31 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License along with
34 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
35 Place, Suite 330, Boston, MA 02111-1307 USA.
36 '''
37 import re, os
38 import bb
39 from   bb import data
40 from   bb.fetch import Fetch
41 from   bb.fetch import FetchError
42 from   bb.fetch import MissingParameterError
43
44
45 __pattern__ = re.compile(r'''
46  \s*                 # Skip leading whitespace
47  ssh://              # scheme
48  (                   # Optional username/password block
49   (?P<user>\S+)      # username
50   (:(?P<pass>\S+))?  # colon followed by the password (optional)
51  )?
52  (?P<cparam>(;[^;]+)*)?  # connection parameters block (optional)
53  @
54  (?P<host>\S+?)          # non-greedy match of the host
55  (:(?P<port>[0-9]+))?    # colon followed by the port (optional)
56  /
57  (?P<path>[^;]+)         # path on the remote system, may be absolute or relative,
58                          # and may include the use of '~' to reference the remote home
59                          # directory
60  (?P<sparam>(;[^;]+)*)?  # parameters block (optional)
61  $
62 ''', re.VERBOSE)
63
64 class SSH(Fetch):
65     '''Class to fetch a module or modules via Secure Shell'''
66
67     def supports(self, url, d):
68         return __pattern__.match(url) != None
69
70     def localpath(self, url, d):
71         m = __pattern__.match(url)
72         path = m.group('path')
73         host = m.group('host')
74         lpath = os.path.join(data.getVar('DL_DIR', d, 1), host, os.path.basename(path))
75         return lpath
76
77     def go(self, d, urls = []):
78         if not urls:
79             urls = self.urls
80
81         for url in urls:
82             dldir = data.getVar('DL_DIR', d, 1)
83
84             m = __pattern__.match(url)
85             path = m.group('path')
86             host = m.group('host')
87             port = m.group('port')
88             user = m.group('user')
89             password = m.group('pass')
90
91             ldir = os.path.join(dldir, host)
92             lpath = os.path.join(ldir, os.path.basename(path))
93
94             if not os.path.exists(ldir):
95                 os.makedirs(ldir)
96
97             if port:
98                 port = '-P %s' % port
99             else:
100                 port = ''
101
102             if user:
103                 fr = user
104                 if password:
105                     fr += ':%s' % password
106                 fr += '@%s' % host
107             else:
108                 fr = host
109             fr += ':%s' % path
110
111
112             import commands
113             cmd = 'scp -B -r %s %s %s/' % (
114                 port,
115                 commands.mkarg(fr),
116                 commands.mkarg(ldir)
117             )
118
119             (exitstatus, output) = commands.getstatusoutput(cmd)
120             if exitstatus != 0:
121                 print output
122                 raise FetchError('Unable to fetch %s' % url)