forked from conan-io/conan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxy.py
172 lines (148 loc) · 7.77 KB
/
proxy.py
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
import os
from requests.exceptions import RequestException
from conans.client.graph.graph import (RECIPE_DOWNLOADED, RECIPE_INCACHE, RECIPE_NEWER,
RECIPE_NOT_IN_REMOTE, RECIPE_NO_REMOTE, RECIPE_UPDATEABLE,
RECIPE_UPDATED, RECIPE_EDITABLE)
from conans.client.output import ScopedOutput
from conans.client.recorder.action_recorder import INSTALL_ERROR_MISSING, INSTALL_ERROR_NETWORK
from conans.client.remover import DiskRemover
from conans.errors import ConanException, NotFoundException, RecipeNotFoundException
from conans.paths.package_layouts.package_editable_layout import PackageEditableLayout
from conans.util.tracer import log_recipe_got_from_local_cache
DEPRECATED_CONAN_CENTER_BINTRAY_URL = "https://conan.bintray.com"
class ConanProxy(object):
def __init__(self, cache, output, remote_manager):
# collaborators
self._cache = cache
self._out = output
self._remote_manager = remote_manager
def get_recipe(self, ref, check_updates, update, remotes, recorder):
layout = self._cache.package_layout(ref)
if isinstance(layout, PackageEditableLayout):
conanfile_path = layout.conanfile()
status = RECIPE_EDITABLE
# TODO: log_recipe_got_from_editable(reference)
# TODO: recorder.recipe_fetched_as_editable(reference)
return conanfile_path, status, None, ref
with layout.conanfile_write_lock(self._out):
result = self._get_recipe(layout, ref, check_updates, update, remotes, recorder)
conanfile_path, status, remote, new_ref = result
if status not in (RECIPE_DOWNLOADED, RECIPE_UPDATED):
log_recipe_got_from_local_cache(new_ref)
recorder.recipe_fetched_from_cache(new_ref)
return conanfile_path, status, remote, new_ref
def _get_recipe(self, layout, ref, check_updates, update, remotes, recorder):
output = ScopedOutput(str(ref), self._out)
# check if it is in disk
conanfile_path = layout.conanfile()
# NOT in disk, must be retrieved from remotes
if not os.path.exists(conanfile_path):
remote, new_ref = self._download_recipe(layout, ref, output, remotes, remotes.selected,
recorder)
status = RECIPE_DOWNLOADED
return conanfile_path, status, remote, new_ref
metadata = layout.load_metadata()
cur_revision = metadata.recipe.revision
cur_remote = metadata.recipe.remote
cur_remote = remotes[cur_remote] if cur_remote else None
selected_remote = remotes.selected or cur_remote
check_updates = check_updates or update
requested_different_revision = (ref.revision is not None) and cur_revision != ref.revision
if requested_different_revision:
if check_updates or self._cache.new_config["core:allow_explicit_revision_update"]:
remote, new_ref = self._download_recipe(layout, ref, output, remotes,
selected_remote, recorder)
status = RECIPE_DOWNLOADED
return conanfile_path, status, remote, new_ref
else:
raise NotFoundException("The '%s' revision recipe in the local cache doesn't "
"match the requested '%s'."
" Use '--update' to check in the remote."
% (cur_revision, repr(ref)))
if not check_updates:
status = RECIPE_INCACHE
ref = ref.copy_with_rev(cur_revision)
return conanfile_path, status, cur_remote, ref
# Checking updates in the server
if not selected_remote:
status = RECIPE_NO_REMOTE
ref = ref.copy_with_rev(cur_revision)
return conanfile_path, status, None, ref
try: # get_recipe_manifest can fail, not in server
upstream_manifest, ref = self._remote_manager.get_recipe_manifest(ref, selected_remote)
except NotFoundException:
status = RECIPE_NOT_IN_REMOTE
ref = ref.copy_with_rev(cur_revision)
return conanfile_path, status, selected_remote, ref
read_manifest = layout.recipe_manifest()
if upstream_manifest != read_manifest:
if upstream_manifest.time > read_manifest.time:
if update:
DiskRemover().remove_recipe(layout, output=output)
output.info("Retrieving from remote '%s'..." % selected_remote.name)
self._download_recipe(layout, ref, output, remotes, selected_remote, recorder)
status = RECIPE_UPDATED
return conanfile_path, status, selected_remote, ref
else:
status = RECIPE_UPDATEABLE
else:
status = RECIPE_NEWER
else:
status = RECIPE_INCACHE
ref = ref.copy_with_rev(cur_revision)
return conanfile_path, status, selected_remote, ref
def _download_recipe(self, layout, ref, output, remotes, remote, recorder):
def _retrieve_from_remote(the_remote):
output.info("Trying with '%s'..." % the_remote.name)
# If incomplete, resolve the latest in server
if the_remote.url.startswith(DEPRECATED_CONAN_CENTER_BINTRAY_URL):
output.warn("Remote https://conan.bintray.com is deprecated and will be shut down "
"soon.")
output.warn("Please use the new 'conancenter' default remote.")
output.warn("Add it to your remotes with: conan remote add -i 0 conancenter "
"https://center.conan.io")
_ref = self._remote_manager.get_recipe(ref, the_remote)
output.info("Downloaded recipe revision %s" % _ref.revision)
recorder.recipe_downloaded(ref, the_remote.url)
return _ref
if remote:
output.info("Retrieving from server '%s' " % remote.name)
else:
try:
remote_name = layout.load_metadata().recipe.remote
if remote_name:
remote = remotes[remote_name]
except (IOError, RecipeNotFoundException):
pass
else:
if remote:
output.info("Retrieving from predefined remote '%s'" % remote.name)
if remote:
try:
new_ref = _retrieve_from_remote(remote)
return remote, new_ref
except NotFoundException:
msg = "%s was not found in remote '%s'" % (str(ref), remote.name)
recorder.recipe_install_error(ref, INSTALL_ERROR_MISSING,
msg, remote.url)
raise NotFoundException(msg)
except RequestException as exc:
recorder.recipe_install_error(ref, INSTALL_ERROR_NETWORK,
str(exc), remote.url)
raise exc
output.info("Not found in local cache, looking in remotes...")
remotes = remotes.values()
if not remotes:
raise ConanException("No remote defined")
for remote in remotes:
try:
new_ref = _retrieve_from_remote(remote)
return remote, new_ref
# If not found continue with the next, else raise
except NotFoundException:
pass
else:
msg = "Unable to find '%s' in remotes" % ref.full_str()
recorder.recipe_install_error(ref, INSTALL_ERROR_MISSING,
msg, None)
raise NotFoundException(msg)