1# This software may be used and distributed according to the terms of the
2# GNU General Public License version 2 or any later version.
3
4from __future__ import absolute_import
5
6import re
7
8from mercurial.i18n import _
9from mercurial.pycompat import getattr
10from mercurial import (
11    error,
12    hg,
13    util,
14)
15from mercurial.utils import (
16    urlutil,
17)
18
19from . import (
20    lfutil,
21    localstore,
22    wirestore,
23)
24
25
26# During clone this function is passed the src's ui object
27# but it needs the dest's ui object so it can read out of
28# the config file. Use repo.ui instead.
29def openstore(repo=None, remote=None, put=False, ui=None):
30    if ui is None:
31        ui = repo.ui
32
33    if not remote:
34        lfpullsource = getattr(repo, 'lfpullsource', None)
35        if put:
36            path = urlutil.get_unique_push_path(
37                b'lfpullsource', repo, ui, lfpullsource
38            )
39        else:
40            path, _branches = urlutil.get_unique_pull_path(
41                b'lfpullsource', repo, ui, lfpullsource
42            )
43
44        # XXX we should not explicitly pass b'default', as this will result in
45        # b'default' being returned if no `paths.default` was defined. We
46        # should explicitely handle the lack of value instead.
47        if repo is None:
48            path, _branches = urlutil.get_unique_pull_path(
49                b'lfs', repo, ui, b'default'
50            )
51            remote = hg.peer(repo or ui, {}, path)
52        elif path == b'default-push' or path == b'default':
53            remote = repo
54        else:
55            path, _branches = urlutil.parseurl(path)
56            remote = hg.peer(repo or ui, {}, path)
57
58    # The path could be a scheme so use Mercurial's normal functionality
59    # to resolve the scheme to a repository and use its path
60    path = util.safehasattr(remote, b'url') and remote.url() or remote.path
61
62    match = _scheme_re.match(path)
63    if not match:  # regular filesystem path
64        scheme = b'file'
65    else:
66        scheme = match.group(1)
67
68    try:
69        storeproviders = _storeprovider[scheme]
70    except KeyError:
71        raise error.Abort(_(b'unsupported URL scheme %r') % scheme)
72
73    for classobj in storeproviders:
74        try:
75            return classobj(ui, repo, remote)
76        except lfutil.storeprotonotcapable:
77            pass
78
79    raise error.Abort(
80        _(b'%s does not appear to be a largefile store')
81        % urlutil.hidepassword(path)
82    )
83
84
85_storeprovider = {
86    b'file': [localstore.localstore],
87    b'http': [wirestore.wirestore],
88    b'https': [wirestore.wirestore],
89    b'ssh': [wirestore.wirestore],
90}
91
92_scheme_re = re.compile(br'^([a-zA-Z0-9+-.]+)://')
93
94
95def getlfile(ui, hash):
96    return util.chunkbuffer(openstore(ui=ui)._get(hash))
97