Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: link editable packages #4181

Merged
merged 148 commits into from
Jan 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
148 commits
Select commit Hold shift + click to select a range
caa5778
first try
jgsogo Oct 19, 2018
9d7ff95
fix includes
jgsogo Oct 19, 2018
badb5a4
Merge remote-tracking branch 'conan/develop' into issue/3559
jgsogo Oct 19, 2018
6a865f4
minor changes
jgsogo Oct 19, 2018
d243084
more import fixes
jgsogo Oct 19, 2018
5ea4a62
fix more imports
jgsogo Oct 19, 2018
67f2a6b
short path as decorator
jgsogo Oct 19, 2018
3d58af1
move SimplePaths to conans/paths/simple_paths.py
jgsogo Oct 19, 2018
fdf38ea
move back constants to conans.paths
jgsogo Oct 19, 2018
55609ff
moving folders to conans.paths
jgsogo Oct 19, 2018
25ec7d5
remove diffs caused just by ordering of imports
jgsogo Oct 19, 2018
bc30193
remove diffs caused just by ordering of imports
jgsogo Oct 19, 2018
5529a75
no diffs
jgsogo Oct 19, 2018
5e85879
no diff
jgsogo Oct 19, 2018
fb01197
move is_case_insensitive_os to conans.paths
jgsogo Oct 19, 2018
0c7e40c
Merge remote-tracking branch 'conan/develop' into issue/3559
jgsogo Oct 19, 2018
6e6bb2d
add rm_conandir to windows imports
jgsogo Oct 22, 2018
2ca5367
Merge branch 'develop' into issue/3559
jgsogo Oct 30, 2018
575e28f
move package_layouts to paths
jgsogo Oct 30, 2018
b9d5b00
fix imports
jgsogo Oct 30, 2018
dc001c4
move LINKED_FOLDER_SENTINEL to conans.paths.__init__.py
jgsogo Oct 30, 2018
cfbeb10
move 'get_package_layout' to 'SimplePaths'
jgsogo Nov 2, 2018
5e37352
get rid of PackageBaseLayout, go for duck typing
jgsogo Nov 2, 2018
ab121e4
add parser for the file that will contain paths to includes, res, bin…
jgsogo Nov 2, 2018
bbc0b3a
rename PackageUserLayout > PackageEditableLayout
jgsogo Nov 2, 2018
3957886
interface for installed_as_editable info
jgsogo Nov 2, 2018
2f1009f
test with a header only editable package
jgsogo Nov 2, 2018
c6ca852
working example for header only lib
jgsogo Nov 2, 2018
78936c2
add test for a library with settings and options (still header only)
jgsogo Nov 2, 2018
50708de
fix py2 test (declare string in source as unicode)
jgsogo Nov 2, 2018
e8078cb
change import to avoid conans.tools one, so we need to mock a differe…
jgsogo Nov 2, 2018
3494a42
make it compatible for win/linux
jgsogo Nov 2, 2018
14a4c32
Merge branch 'feature/editable-packages' into issue/3559
jgsogo Nov 23, 2018
e76e8c6
create the editable file sentinel using --editable argument in instal…
jgsogo Nov 23, 2018
9e57437
add needed functions to simple_paths
jgsogo Nov 23, 2018
08a343f
Merge branch 'feature/editable-packages' into feature/editable-packag…
jgsogo Nov 23, 2018
ef65d20
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Nov 23, 2018
6ce86ff
add helper functions to simple paths
jgsogo Nov 23, 2018
e437a98
Merge branch 'issue/3559' into feature/editable-packages-consuming
jgsogo Nov 23, 2018
dcbd72c
Merge branch 'feature/editable-packages' into issue/3559
jgsogo Nov 23, 2018
19a7ad1
add package_metadata to new layouts
jgsogo Nov 23, 2018
d54eb45
Merge branch 'issue/3559' into feature/editable-packages-consuming
jgsogo Nov 23, 2018
0efe349
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Nov 23, 2018
102ff6e
add missing named var (something went wrong merging from develop)
jgsogo Nov 26, 2018
16833fd
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Nov 26, 2018
fc3bda6
remove lines, not anymore there
jgsogo Nov 26, 2018
158ba05
add package metadata to users one
jgsogo Nov 26, 2018
5b3a46e
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Nov 26, 2018
5cc6057
handle error: package folders needs a ConanFileReference
jgsogo Nov 26, 2018
c8397d6
Merge branch 'feature/editable-packages' into issue/3559
jgsogo Dec 7, 2018
f19f9af
reorder imports
jgsogo Dec 7, 2018
bfff346
Merge branch 'issue/3559' into feature/editable-packages-consuming
jgsogo Dec 7, 2018
15550ab
add missing import
jgsogo Dec 7, 2018
ebb67ac
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Dec 7, 2018
ce8eb9b
reorder imports
jgsogo Dec 7, 2018
7c6db05
if an editable package is dirty, log an error
jgsogo Dec 7, 2018
5f1301b
moved parser to conan_file
jgsogo Dec 10, 2018
22fc401
move parsing for conan_package_layout closer to the ConanFile, we wil…
jgsogo Dec 10, 2018
511adac
placeholders should be preprended with settings|options
jgsogo Dec 10, 2018
12fb129
fix typos, remove unused code
jgsogo Dec 10, 2018
ff3557a
fix bug/typo
jgsogo Dec 10, 2018
48cc571
order imports
jgsogo Dec 11, 2018
9b622cb
remove unreachable code
jgsogo Dec 12, 2018
0bb7a5c
Merge pull request #3804 from jgsogo/issue/3559
jgsogo Dec 12, 2018
5f6197b
Merge remote-tracking branch 'conan/feature/editable-packages' into f…
jgsogo Dec 12, 2018
087439a
remove unreachable code
jgsogo Dec 12, 2018
63edf5c
remove comments
jgsogo Dec 12, 2018
dcf2c95
move unittests to its folder
jgsogo Dec 12, 2018
ec9258a
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Dec 12, 2018
a95edf3
install as editable (requires the package to be already in the cache)
jgsogo Dec 12, 2018
6591ff9
declare tests
jgsogo Dec 12, 2018
f7d796b
refactor the editable hack: rely on member attribute
jgsogo Dec 14, 2018
f18f272
move imports
jgsogo Dec 14, 2018
15b77f1
rename file to match class name
jgsogo Dec 14, 2018
7118f0b
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Dec 14, 2018
115a05c
notify user about editable condition
jgsogo Dec 14, 2018
9d2394e
gather logic together
jgsogo Dec 14, 2018
2d3f8ac
Merge branch 'feature/editable-packages-consuming' into feature/creat…
jgsogo Dec 14, 2018
fcec08c
make it editable from the very beginning, we don't care if it is edit…
jgsogo Dec 14, 2018
bd0428a
any error will require us to delete the editable flag
jgsogo Dec 14, 2018
d5e0a59
add tests
jgsogo Dec 14, 2018
600c2d8
add tests related to editable package removal
jgsogo Dec 14, 2018
19a5ab9
rename tests
jgsogo Dec 14, 2018
a849d28
add test for other commands
jgsogo Dec 17, 2018
5e4f581
add tests for conan commands
jgsogo Dec 17, 2018
d95f34c
Update conans/test/command/editable_reference/create_editable_package…
danimtb Dec 17, 2018
584619d
add changes from review
jgsogo Dec 17, 2018
f4e161e
Merge remote-tracking branch 'conan/develop' into feature/create-edit…
jgsogo Dec 17, 2018
172e592
move tests to final location
jgsogo Dec 17, 2018
ae835cf
remove unused var
jgsogo Dec 17, 2018
233928c
change variable name (it was a py conanfile)
jgsogo Dec 17, 2018
86f059f
don0t care about the output, but check something
jgsogo Dec 17, 2018
5f69dc9
remove comments
jgsogo Dec 17, 2018
61e4739
add tests installing an editable package (and installing its dependen…
jgsogo Dec 18, 2018
b0b9559
remove unused import
jgsogo Dec 18, 2018
99f4384
move cpp_info overrides to an standalone model
jgsogo Dec 18, 2018
3408b5e
minor changes related to reviews
jgsogo Dec 18, 2018
d7195c4
mode create/remove editables to client_cache class
jgsogo Dec 18, 2018
0b126d2
renamed test folder
jgsogo Dec 18, 2018
0e7716e
remove code related to 'install --editable'
jgsogo Dec 18, 2018
69f3596
link/unlink editable packages
jgsogo Dec 19, 2018
d5e20fa
consider these tests
jgsogo Dec 19, 2018
1b8adcc
handle remove command on editable
jgsogo Dec 19, 2018
2b2b4cf
Merge branch 'feature/create-editable-packages' into feature/link-edi…
jgsogo Dec 19, 2018
0982d8c
adapt message
jgsogo Dec 19, 2018
94c75a7
removal is on its own test
jgsogo Dec 19, 2018
997684f
check after unlink
jgsogo Dec 19, 2018
2967fa0
add tests using linked packages
jgsogo Dec 20, 2018
8bfbe6e
add tests for several commands
jgsogo Dec 20, 2018
9bfb90e
fix test related to utf8 and ordering
jgsogo Dec 20, 2018
e075cef
apply ordering
jgsogo Dec 20, 2018
a22d415
remove prints
jgsogo Dec 20, 2018
a95ecea
putting path between quotes seems to solve windows issue
jgsogo Dec 20, 2018
b750a86
review (add more checks in tests)
jgsogo Dec 20, 2018
e13436c
Merge remote-tracking branch 'conan/develop' into feature/link-editab…
jgsogo Dec 21, 2018
43bcbe5
function changed its name
jgsogo Dec 21, 2018
720ade3
no import in __init__.py
jgsogo Dec 24, 2018
8629acc
remove installed as editable
jgsogo Dec 24, 2018
9e12f3d
Merge remote-tracking branch 'conan/develop' into feature/link-editab…
jgsogo Dec 24, 2018
da3128f
order is not guaranteed on info command output
jgsogo Dec 24, 2018
12a0e7f
no need for os.path.join
jgsogo Dec 24, 2018
d1c71c0
move EDITABLE before locking package layout
jgsogo Dec 24, 2018
a12f4a5
no different behaviour for update
jgsogo Dec 24, 2018
9910e12
new model for editable_cpp_info
jgsogo Dec 26, 2018
9e547ff
check that cache file has more priority than the repo one
jgsogo Dec 26, 2018
7c14776
review
jgsogo Jan 4, 2019
e49a4b5
remove test, it is accepted behaviour now
jgsogo Jan 4, 2019
0446215
Merge pull request #8 from jgsogo/feature/link-editable-packages-files
jgsogo Jan 4, 2019
b6adc07
review
jgsogo Jan 4, 2019
f980339
revert change, this line is needed to pass tests in Windows
jgsogo Jan 4, 2019
116dad7
weird substitution is not needed, but path normalization is
jgsogo Jan 4, 2019
07fee28
inform about link removal
jgsogo Jan 8, 2019
a6fae63
use conditional 'strict' arg when reusing cache for several TestClients
jgsogo Jan 8, 2019
15de030
pass string to conan_api, build ConanFileReference inside it
jgsogo Jan 8, 2019
54f5bf7
add tests case for editable package without files, it will use packag…
jgsogo Jan 8, 2019
50d2f11
remove unused import
jgsogo Jan 8, 2019
2fcb03e
remove uneeded command
jgsogo Jan 8, 2019
fb97849
Merge remote-tracking branch 'conan/develop' into feature/link-editab…
jgsogo Jan 9, 2019
8706806
get the path to the conanfile.py from the argument to 'link' command …
jgsogo Jan 9, 2019
1afbc1d
remove 'EditableCppInfo.create', rename loader ones to 'load(file...)…
jgsogo Jan 9, 2019
77b2f7b
rename func argument
jgsogo Jan 9, 2019
f40db78
move CONAN_PACKAGE_LAYOUT_FILE to conans/paths
jgsogo Jan 9, 2019
1b9cfae
reorder variables inside file
jgsogo Jan 9, 2019
7e1dc41
renamed variables
jgsogo Jan 9, 2019
6a5d04b
pep8
jgsogo Jan 10, 2019
73bc361
not using revisions in editable nodes, fix ordering issue
memsharded Jan 10, 2019
fefd5f2
Merge branch 'feature/link-editable-packages' of github.com:jgsogo/co…
jgsogo Jan 10, 2019
9093a0a
rename variables
jgsogo Jan 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions conans/client/client_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from conans.model.profile import Profile
from conans.model.ref import ConanFileReference
from conans.model.settings import Settings
from conans.paths import CONAN_MANIFEST, PUT_HEADERS, SimplePaths, check_ref_case
from conans.paths import CONAN_MANIFEST, PUT_HEADERS
from conans.paths.simple_paths import SimplePaths
from conans.unicode import get_cwd
from conans.util.files import list_folder_subdirs, load, normalize, save
from conans.util.locks import Lock, NoLock, ReadLock, SimpleLock, WriteLock
Expand All @@ -28,6 +29,9 @@
REGISTRY_JSON = "registry.json"
PROFILES_FOLDER = "profiles"
HOOKS_FOLDER = "hooks"
LAYOUTS_FOLDER = 'layouts'

DEFAULT_LAYOUT_FILE = "default"

# Client certificates
CLIENT_CERT = "client.crt"
Expand Down Expand Up @@ -163,6 +167,10 @@ def default_profile_path(self):
return join(self.conan_folder, PROFILES_FOLDER,
self.conan_config.default_profile)

@property
def default_editable_path(self):
return os.path.join(self.conan_folder, LAYOUTS_FOLDER, DEFAULT_LAYOUT_FILE)

@property
def hooks_path(self):
"""
Expand Down Expand Up @@ -252,7 +260,6 @@ def load_manifest(self, conan_reference):
"""conan_id = sha(zip file)"""
assert isinstance(conan_reference, ConanFileReference)
export_folder = self.export(conan_reference)
check_ref_case(conan_reference, export_folder, self.store)
return FileTreeManifest.load(export_folder)

def load_package_manifest(self, package_reference):
Expand Down Expand Up @@ -321,6 +328,17 @@ def package_summary_hash(self, package_ref):
readed_digest = FileTreeManifest.load(package_folder)
return readed_digest.summary_hash

def install_as_editable(self, conan_reference, target_path):
linked_folder_sentinel = self._build_path_to_linked_folder_sentinel(conan_reference)
save(linked_folder_sentinel, content=target_path)

def remove_editable(self, conan_reference):
if self.installed_as_editable(conan_reference):
jgsogo marked this conversation as resolved.
Show resolved Hide resolved
linked_folder_sentinel = self._build_path_to_linked_folder_sentinel(conan_reference)
os.remove(linked_folder_sentinel)
return True
return False


def _mix_settings_with_env(settings):
"""Reads CONAN_ENV_XXXX variables from environment
Expand Down
39 changes: 37 additions & 2 deletions conans/client/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
from conans.client.cmd.uploader import UPLOAD_POLICY_FORCE, \
UPLOAD_POLICY_NO_OVERWRITE, UPLOAD_POLICY_NO_OVERWRITE_RECIPE, UPLOAD_POLICY_SKIP
from conans.client.conan_api import (Conan, default_manifest_folder)
from conans.client.conan_api import _get_conanfile_path
from conans.client.conan_command_output import CommandOutputer
from conans.client.output import Color
from conans.client.printer import Printer
from conans.client.tools.files import save
from conans.errors import ConanException, ConanInvalidConfiguration, NoRemoteAvailable
from conans.model.ref import ConanFileReference
from conans.unicode import get_cwd
from conans.util.config_parser import get_bool_from_text
from conans.util.files import exception_message_safe
from conans.util.files import save
from conans.util.log import logger

# Exit codes for conan command:
Expand Down Expand Up @@ -1332,12 +1333,46 @@ def alias(self, *args):

self._conan.export_alias(args.reference, args.target)

def link(self, *args):
""" Links a conan reference (e.g lib/1.0@conan/stable) with a local folder path.

"""
parser = argparse.ArgumentParser(description=self.link.__doc__,
prog="conan link")
parser.add_argument('target', help='Path to the package folder in the user workspace',
nargs='?',)
parser.add_argument('reference', help='Reference to link. e.g.: mylib/1.X@user/channel')
parser.add_argument("--remove", action='store_true', default=False,
help='Remove linked reference (target not required)')

args = parser.parse_args(*args)
self._warn_python2()

# Args sanity check
if args.remove and args.target:
raise ConanException("Do not provide the 'target' argument for removal")

if not args.remove and not args.target:
raise ConanException("Argument 'target' is required to link a reference")

if not args.remove:
self._conan.link(args.target, args.reference, cwd=os.getcwd())
self._outputer.writeln("Reference '{}' linked to directory "
"'{}'".format(args.reference, os.path.dirname(args.target)))
else:
ret = self._conan.unlink(args.reference)
if ret:
self._outputer.writeln("Removed linkage for reference '{}'".format(args.reference))
else:
self._user_io.out.warn("Reference '{}' was not installed "
"as editable".format(args.reference))

def _show_help(self):
"""Prints a summary of all commands
"""
grps = [("Consumer commands", ("install", "config", "get", "info", "search")),
("Creator commands", ("new", "create", "upload", "export", "export-pkg", "test")),
("Package development commands", ("source", "build", "package")),
("Package development commands", ("source", "build", "package", "link")),
("Misc commands", ("profile", "remote", "user", "imports", "copy", "remove",
"alias", "download", "inspect", "help"))]

Expand Down
22 changes: 21 additions & 1 deletion conans/client/conan_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
from conans.model.ref import ConanFileReference, PackageReference, check_valid_ref
from conans.model.version import Version
from conans.model.workspace import Workspace
from conans.paths import BUILD_INFO, CONANINFO, get_conan_user_home
from conans.paths import BUILD_INFO, CONANINFO, get_conan_user_home, CONAN_PACKAGE_LAYOUT_FILE
from conans.tools import set_global_instances
from conans.unicode import get_cwd
from conans.util.env_reader import get_env
Expand Down Expand Up @@ -933,6 +933,26 @@ def get_default_remote(self):
def get_remote_by_name(self, remote_name):
return self._client_cache.registry.remotes.get(remote_name)

@api_method
def link(self, target_path, target_reference, cwd):
# Retrieve conanfile.py from target_path
target_path = _get_conanfile_path(path=target_path, cwd=cwd, py=True)

ref = ConanFileReference.loads(target_reference, validate=True)
target_conanfile = self._graph_manager._loader.load_class(target_path)
if (target_conanfile.name and target_conanfile.name != ref.name) or \
(target_conanfile.version and target_conanfile.version != ref.version):
raise ConanException("Name and version from reference ({}) and target "
"conanfile.py ({}/{}) must match".
format(ref, target_conanfile.name, target_conanfile.version))

self._client_cache.install_as_editable(ref, os.path.dirname(target_path))

@api_method
def unlink(self, reference):
ref = ConanFileReference.loads(reference, validate=True)
return self._client_cache.remove_editable(ref)


Conan = ConanAPIV1

Expand Down
3 changes: 2 additions & 1 deletion conans/client/conan_command_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from conans.search.binary_html_table import html_binary_graph
from conans.unicode import get_cwd
from conans.util.files import save
from conans.client.graph.graph import RECIPE_EDITABLE


class CommandOutputer(object):
Expand Down Expand Up @@ -73,7 +74,7 @@ def _read_dates(self, deps_graph):
ret = {}
for node in sorted(deps_graph.nodes):
ref = node.conan_ref
if node.recipe not in (RECIPE_CONSUMER, RECIPE_VIRTUAL):
if node.recipe not in (RECIPE_CONSUMER, RECIPE_VIRTUAL, RECIPE_EDITABLE):
manifest = self.client_cache.load_manifest(ref)
ret[ref] = manifest.time_str
return ret
Expand Down
6 changes: 6 additions & 0 deletions conans/client/graph/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
RECIPE_UPDATEABLE = "Update available" # The update of the recipe is available (only in conan info)
RECIPE_NO_REMOTE = "No remote"
RECIPE_WORKSPACE = "Workspace"
RECIPE_EDITABLE = "Editable"
RECIPE_CONSUMER = "Consumer" # A conanfile from the user
RECIPE_VIRTUAL = "Virtual" # A virtual conanfile (dynamic in memory conanfile)

Expand All @@ -22,6 +23,7 @@
BINARY_MISSING = "Missing"
BINARY_SKIP = "Skip"
BINARY_WORKSPACE = "Workspace"
BINARY_EDITABLE = "Editable"


class Node(object):
Expand Down Expand Up @@ -99,6 +101,10 @@ def __cmp__(self, other):
if self.conan_ref.revision is not None and other.conan_ref.revision is None:
return -1

if self.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL):
return 1
if other.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL):
return -1
if self.conan_ref < other.conan_ref:
return -1

Expand Down
11 changes: 10 additions & 1 deletion conans/client/graph/graph_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

from conans.client.graph.graph import (BINARY_BUILD, BINARY_CACHE, BINARY_DOWNLOAD, BINARY_MISSING,
BINARY_SKIP, BINARY_UPDATE, BINARY_WORKSPACE,
RECIPE_EDITABLE, BINARY_EDITABLE,
RECIPE_CONSUMER, RECIPE_VIRTUAL)
from conans.client.output import ScopedOutput
from conans.errors import NoRemoteAvailable, NotFoundException
from conans.model.info import ConanInfo
from conans.model.manifest import FileTreeManifest
Expand Down Expand Up @@ -74,6 +76,11 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_
evaluated_references[package_ref] = node

output = conanfile.output

if node.recipe == RECIPE_EDITABLE:
node.binary = BINARY_EDITABLE
return

if build_mode.forced(conanfile, conan_ref):
output.warn('Forced build from source')
node.binary = BINARY_BUILD
Expand All @@ -91,7 +98,8 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_
with self._client_cache.package_lock(package_ref):
if is_dirty(package_folder):
output.warn("Package is corrupted, removing folder: %s" % package_folder)
rmdir(package_folder)
assert node.recipe != RECIPE_EDITABLE, "Editable package cannot be dirty"
jgsogo marked this conversation as resolved.
Show resolved Hide resolved
rmdir(package_folder) # Do not remove if it is EDITABLE

if remote_name:
remote = self._registry.remotes.get(remote_name)
Expand All @@ -116,6 +124,7 @@ def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_
if not node.binary:
node.binary = BINARY_CACHE
package_hash = ConanInfo.load_from_package(package_folder).recipe_hash

else: # Binary does NOT exist locally
if not revisions_enabled and not node.revision_pinned:
# Do not search for packages for the specific resolved recipe revision but all
Expand Down
9 changes: 8 additions & 1 deletion conans/client/graph/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from conans.client.graph.graph import (RECIPE_DOWNLOADED, RECIPE_INCACHE, RECIPE_NEWER,
RECIPE_NOT_IN_REMOTE, RECIPE_NO_REMOTE, RECIPE_UPDATEABLE,
RECIPE_UPDATED)
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
Expand All @@ -23,6 +23,13 @@ def __init__(self, client_cache, output, remote_manager):
self._registry = client_cache.registry

def get_recipe(self, conan_reference, check_updates, update, remote_name, recorder):
if self._client_cache.installed_as_editable(conan_reference):
conanfile_path = self._client_cache.conanfile(conan_reference)
status = RECIPE_EDITABLE
# TODO: log_recipe_got_from_editable(reference)
# TODO: recorder.recipe_fetched_as_editable(reference)
return conanfile_path, status, None, conan_reference

with self._client_cache.conanfile_write_lock(conan_reference):
result = self._get_recipe(conan_reference, check_updates, update, remote_name, recorder)
conanfile_path, status, remote, reference = result
Expand Down
43 changes: 42 additions & 1 deletion conans/client/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from conans.client.file_copier import report_copied_files
from conans.client.generators import TXTGenerator, write_generators
from conans.client.graph.graph import BINARY_BUILD, BINARY_CACHE, BINARY_DOWNLOAD, BINARY_MISSING, \
BINARY_SKIP, BINARY_UPDATE
BINARY_SKIP, BINARY_UPDATE, BINARY_EDITABLE
from conans.client.importer import remove_imports
from conans.client.output import ScopedOutput
from conans.client.packager import create_package
Expand All @@ -19,6 +19,7 @@
conanfile_exception_formatter)
from conans.model.build_info import CppInfo
from conans.model.conan_file import get_env_context_manager
from conans.model.editable_cpp_info import EditableCppInfo
from conans.model.env_info import EnvInfo
from conans.model.manifest import FileTreeManifest
from conans.model.ref import PackageReference
Expand Down Expand Up @@ -265,6 +266,7 @@ def __init__(self, client_cache, output, remote_manager, recorder, workspace, ho
self._recorder = recorder
self._workspace = workspace
self._hook_manager = hook_manager
self._editable_cpp_info = self._load_editables_cpp_info()

def install(self, deps_graph, keep_build=False, graph_info=None):
# order by levels and separate the root node (conan_ref=None) from the rest
Expand All @@ -288,6 +290,10 @@ def _build(self, nodes_by_level, deps_graph, keep_build, root_node, graph_info):
raise_package_not_found_error(conan_file, conan_ref, package_id, dependencies,
out=output, recorder=self._recorder)

if node.binary == BINARY_EDITABLE:
self._handle_node_editable(node)
continue

workspace_package = self._workspace[node.conan_ref] if self._workspace else None
if workspace_package:
self._handle_node_workspace(node, workspace_package, inverse_levels, deps_graph,
Expand All @@ -311,6 +317,41 @@ def _node_concurrently_installed(self, node, package_folder):
if node.update_manifest == read_manifest:
return True

def _load_editables_cpp_info(self):
editables_path = self._client_cache.default_editable_path
if os.path.exists(editables_path):
return EditableCppInfo.load(editables_path, require_namespace=True)
return None

def _handle_node_editable(self, node):
# Get source of information
package_layout = self._client_cache.package_layout(node.conan_ref)
base_path = package_layout.conan()
self._call_package_info(node.conanfile, package_folder=base_path)

# Try with package-provided file
package_layout_file = package_layout.editable_package_layout_file()
if os.path.exists(package_layout_file):
editable_cpp_info = EditableCppInfo.load(package_layout_file,
require_namespace=False)
editable_cpp_info.apply_to(node.conanfile.name,
node.conanfile.cpp_info,
base_path=base_path,
settings=node.conanfile.settings,
options=node.conanfile.options)

# Try with the profile-like file
elif self._editable_cpp_info and self._editable_cpp_info.has_info_for(node.conanfile.name):
self._editable_cpp_info.apply_to(node.conanfile.name,
node.conanfile.cpp_info,
base_path=base_path,
settings=node.conanfile.settings,
options=node.conanfile.options)

# Use `package_info()` data
else:
pass # It will use `package_info()` data relative to path used as 'package_folder'

def _handle_node_cache(self, node, package_ref, keep_build, processed_package_references):
conan_file = node.conanfile
output = conan_file.output
Expand Down
4 changes: 2 additions & 2 deletions conans/client/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from conans.client.client_cache import ClientCache
from conans.client.generators import write_generators
from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL
from conans.client.graph.printer import print_graph
from conans.client.importer import run_deploy, run_imports
from conans.client.installer import BinaryInstaller, call_system_requirements
Expand All @@ -14,7 +15,6 @@
from conans.model.ref import ConanFileReference
from conans.paths import CONANINFO
from conans.util.files import normalize, save
from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL


class ConanManager(object):
Expand Down Expand Up @@ -52,7 +52,7 @@ def install(self, reference, install_folder, graph_info, remote_name=None, build
""" Fetch and build all dependencies for the given reference
@param reference: ConanFileReference or path to user space conanfile
@param install_folder: where the output files will be saved
@param remote: install only from that remote
@param remote_name: install only from that remote
@param profile: Profile object with both the -s introduced options and profile read values
@param build_modes: List of build_modes specified
@param update: Check for updated in the upstream remotes (and update)
Expand Down
4 changes: 2 additions & 2 deletions conans/client/manifest_manager.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import os

from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL
from conans.client.remote_registry import Remote
from conans.errors import ConanException
from conans.model.manifest import FileTreeManifest
from conans.model.ref import PackageReference
from conans.paths import SimplePaths
from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL
from conans.paths.simple_paths import SimplePaths


class ManifestManager(object):
Expand Down
2 changes: 1 addition & 1 deletion conans/client/printer.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from conans.client.output import Color
from conans.model.options import OptionsValues
from conans.model.ref import ConanFileReference, PackageReference
from conans.paths import SimplePaths
from conans.paths.simple_paths import SimplePaths
from conans.util.env_reader import get_env
from conans.client.graph.graph import RECIPE_CONSUMER, RECIPE_VIRTUAL

Expand Down
Loading