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

Allow specifying a custom output for the deployers #13757

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 2 additions & 4 deletions conan/api/subapi/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from conans.client.generators import write_generators
from conans.client.installer import BinaryInstaller
from conans.errors import ConanInvalidConfiguration
from conans.util.files import mkdir


class InstallAPI:
Expand Down Expand Up @@ -41,7 +40,7 @@ def install_sources(self, graph, remotes):

# TODO: Look for a better name
def install_consumer(self, deps_graph, generators=None, source_folder=None, output_folder=None,
deploy=False):
deploy=False, deploy_folder=None):
""" Once a dependency graph has been installed, there are things to be done, like invoking
generators for the root consumer.
This is necessary for example for conanfile.txt/py, or for "conan install <ref> -g
Expand All @@ -63,8 +62,7 @@ def install_consumer(self, deps_graph, generators=None, source_folder=None, outp

# The previous .set_base_folders has already decided between the source_folder and output
if deploy:
base_folder = conanfile.folders.base_build
mkdir(base_folder)
base_folder = deploy_folder or conanfile.folders.base_build
do_deploys(self.conan_api, deps_graph, deploy, base_folder)

conanfile.generators = list(set(conanfile.generators).union(generators or []))
Expand Down
5 changes: 3 additions & 2 deletions conan/cli/commands/graph.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import json
import os

from conan.api.output import ConanOutput, cli_out_write, Color
from conan.cli import make_abs_path
from conan.cli.args import common_graph_args, validate_common_graph_args
Expand Down Expand Up @@ -119,6 +118,8 @@ def graph_info(conan_api, parser, subparser, *args):
help='Print information only for packages that match the patterns')
subparser.add_argument("-d", "--deployer", action="append",
help='Deploy using the provided deployer to the output folder')
subparser.add_argument("-df", "--deployer-folder",
help="Deployer output folder, base build folder by default if not set")
subparser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
args = parser.parse_args(*args)
Expand Down Expand Up @@ -169,7 +170,7 @@ def graph_info(conan_api, parser, subparser, *args):
clean=args.lockfile_clean)
conan_api.lockfile.save_lockfile(lockfile, args.lockfile_out, cwd)
if args.deployer:
base_folder = os.getcwd()
base_folder = args.deployer_folder or os.getcwd()
do_deploys(conan_api, deps_graph, args.deployer, base_folder)

return {"graph": deps_graph,
Expand Down
5 changes: 4 additions & 1 deletion conan/cli/commands/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def install(conan_api, parser, *args):
help='The root output folder for generated and build files')
parser.add_argument("-d", "--deployer", action="append",
help='Deploy using the provided deployer to the output folder')
parser.add_argument("--deployer-folder",
help="Deployer output folder, base build folder by default if not set")
parser.add_argument("--build-require", action='store_true', default=False,
help='Whether the provided reference is a build-require')
args = parser.parse_args(*args)
Expand Down Expand Up @@ -83,7 +85,8 @@ def install(conan_api, parser, *args):
generators=args.generator,
output_folder=output_folder,
source_folder=source_folder,
deploy=args.deployer
deploy=args.deployer,
deploy_folder=args.deployer_folder
)

out.success("Install finished successfully")
Expand Down
3 changes: 2 additions & 1 deletion conan/internal/deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from conans.client.cache.cache import ClientCache
from conans.client.loader import load_python_file
from conans.errors import ConanException
from conans.util.files import rmdir
from conans.util.files import rmdir, mkdir


def _find_deployer(d, cache_deploy_folder):
Expand Down Expand Up @@ -36,6 +36,7 @@ def _load(path):


def do_deploys(conan_api, graph, deploy, deploy_folder):
mkdir(deploy_folder)
# Handle the deploys
cache = ClientCache(conan_api.cache_folder)
for d in deploy or []:
Expand Down
49 changes: 34 additions & 15 deletions conans/test/functional/command/test_install_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ def deploy(graph, output_folder, **kwargs):
"main.cpp": gen_function_cpp(name="main", includes=["hello"], calls=["hello"])},
clean_first=True)
c.run("install . -o *:shared=True "
"--deploy=deploy.py -of=mydeploy -g CMakeToolchain -g CMakeDeps")
"--deployer=deploy.py -of=mydeploy -g CMakeToolchain -g CMakeDeps")
c.run("remove * -c") # Make sure the cache is clean, no deps there
arch = c.get_default_host_profile().settings['arch']
deps = c.load(f"mydeploy/hello-release-{arch}-data.cmake")
Expand Down Expand Up @@ -119,7 +119,7 @@ def test_install_full_deploy_layout(client):
"CMakeLists.txt": cmake,
"main.cpp": gen_function_cpp(name="main", includes=["hello"], calls=["hello"])},
clean_first=True)
c.run("install . -o *:shared=True --deploy=full_deploy.py")
c.run("install . -o *:shared=True --deployer=full_deploy.py")
c.run("remove * -c") # Make sure the cache is clean, no deps there
arch = c.get_default_host_profile().settings['arch']
folder = "/Release" if platform.system() != "Windows" else ""
Expand Down Expand Up @@ -166,7 +166,7 @@ def deploy(graph, output_folder, **kwargs):
"hello/conanfile.py": GenConanfile("hello", "0.1").with_package_file("bin/file.txt",
"content!!")})
c.run("create hello")
c.run("install . --deploy=deploy.py -of=mydeploy")
c.run("install . --deployer=deploy.py -of=mydeploy")


def test_multi_deploy():
Expand Down Expand Up @@ -198,13 +198,13 @@ def deploy(graph, output_folder, **kwargs):
"mydeploy.py": deploy1,
"sub/mydeploy2.py": deploy2})

c.run("install . --deploy=mydeploy --deploy=sub/mydeploy2 --deploy=deploy_cache")
c.run("install . --deployer=mydeploy --deployer=sub/mydeploy2 --deployer=deploy_cache")
assert "conanfile.txt: deploy1!!" in c.out
assert "conanfile.txt: sub/deploy2!!" in c.out
assert "conanfile.txt: deploy cache!!" in c.out

# Now with .py extension
c.run("install . --deploy=mydeploy.py --deploy=sub/mydeploy2.py --deploy=deploy_cache.py")
c.run("install . --deployer=mydeploy.py --deployer=sub/mydeploy2.py --deployer=deploy_cache.py")
assert "conanfile.txt: deploy1!!" in c.out
assert "conanfile.txt: sub/deploy2!!" in c.out
assert "conanfile.txt: deploy cache!!" in c.out
Expand All @@ -226,7 +226,7 @@ def deploy(graph, output_folder, **kwargs):
save(os.path.join(c.cache_folder, "extensions", "deployers", "deploy_cache.py"), deploy_cache)
save(os.path.join(c.cache_folder, "extensions", "deployers", "helper.py"), helper)
c.save({"conanfile.txt": ""})
c.run("install . --deploy=deploy_cache")
c.run("install . --deployer=deploy_cache")
assert "conanfile.txt: My HELPER!!" in c.out


Expand All @@ -252,9 +252,9 @@ def package_info(self):
c.run("create . --name=dep --version=0.1")
c.run("create . --name=dep --version=0.1 -s build_type=Debug -s arch=x86")
c.save({"conanfile.txt": "[requires]\ndep/0.1"}, clean_first=True)
c.run("install . --deploy=full_deploy -of=output -g CMakeDeps")
c.run("install . --deployer=full_deploy -of=output -g CMakeDeps")
assert "Conan built-in full deployer" in c.out
c.run("install . --deploy=full_deploy -of=output -g CMakeDeps "
c.run("install . --deployer=full_deploy -of=output -g CMakeDeps "
"-s build_type=Debug -s arch=x86")

host_arch = c.get_default_host_profile().settings['arch']
Expand All @@ -281,14 +281,14 @@ def test_deploy_reference():
c.save({"conanfile.py": GenConanfile("pkg", "1.0").with_package_file("include/hi.h", "hi")})
c.run("create .")

c.run("install --requires=pkg/1.0 --deploy=full_deploy --output-folder=output")
c.run("install --requires=pkg/1.0 --deployer=full_deploy --output-folder=output")
# NOTE: Full deployer always use build_type/arch, even if None/None in the path, same structure
header = c.load("output/full_deploy/host/pkg/1.0/include/hi.h")
assert "hi" in header

# Testing that we can deploy to the current folder too
c.save({}, clean_first=True)
c.run("install --requires=pkg/1.0 --deploy=full_deploy")
c.run("install --requires=pkg/1.0 --deployer=full_deploy")
# NOTE: Full deployer always use build_type/arch, even if None/None in the path, same structure
header = c.load("full_deploy/host/pkg/1.0/include/hi.h")
assert "hi" in header
Expand All @@ -301,14 +301,14 @@ def test_deploy_overwrite():
c.save({"conanfile.py": GenConanfile("pkg", "1.0").with_package_file("include/hi.h", "hi")})
c.run("create .")

c.run("install --requires=pkg/1.0 --deploy=full_deploy --output-folder=output")
c.run("install --requires=pkg/1.0 --deployer=full_deploy --output-folder=output")
header = c.load("output/full_deploy/host/pkg/1.0/include/hi.h")
assert "hi" in header

# modify the package
c.save({"conanfile.py": GenConanfile("pkg", "1.0").with_package_file("include/hi.h", "bye")})
c.run("create .")
c.run("install --requires=pkg/1.0 --deploy=full_deploy --output-folder=output")
c.run("install --requires=pkg/1.0 --deployer=full_deploy --output-folder=output")
header = c.load("output/full_deploy/host/pkg/1.0/include/hi.h")
assert "bye" in header

Expand All @@ -325,7 +325,7 @@ def test_deploy_editable():

# If we don't change to another folder, the full_deploy will be recursive and fail
with c.chdir(temp_folder()):
c.run("install --requires=pkg/1.0 --deploy=full_deploy --output-folder=output")
c.run("install --requires=pkg/1.0 --deployer=full_deploy --output-folder=output")
header = c.load("output/full_deploy/host/pkg/1.0/src/include/hi.h")
assert "hi" in header

Expand All @@ -339,11 +339,30 @@ def test_deploy_single_package():
c.run("create .")

# if we deploy one --requires, we get that package
c.run("install --requires=pkg/1.0 --deploy=direct_deploy --output-folder=output")
c.run("install --requires=pkg/1.0 --deployer=direct_deploy --output-folder=output")
header = c.load("output/direct_deploy/pkg/include/hi.h")
assert "hi" in header

# If we deploy a local conanfile.txt, we get deployed its direct dependencies
c.run("install consumer/conanfile.txt --deploy=direct_deploy --output-folder=output2")
c.run("install consumer/conanfile.txt --deployer=direct_deploy --output-folder=output2")
header = c.load("output2/direct_deploy/pkg/include/hi.h")
assert "hi" in header


def test_deploy_output_locations():
tc = TestClient()
deployer = textwrap.dedent("""
def deploy(graph, output_folder, **kwargs):
graph.root.conanfile.output.info(f"Deployer output: {output_folder}")
""")
tc.save({"conanfile.txt": "",
"my_deploy.py": deployer})

tmp_folder = temp_folder()
tc.run(f"install . --deployer=my_deploy -of='{tmp_folder}'")
assert f"Deployer output: {tmp_folder}" in tc.out

deployer_output = temp_folder()
tc.run(f"install . --deployer=my_deploy -of='{tmp_folder}' --deployer-folder='{deployer_output}'")
assert f"Deployer output: {deployer_output}" in tc.out
assert f"Deployer output: {tmp_folder}" not in tc.out
4 changes: 2 additions & 2 deletions conans/test/functional/toolchains/cmake/test_ninja.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def test_locally_build_linux(build_type, shared, client):
client.run("create . --name=hello --version=1.0 {}".format(settings))
assert 'cmake -G "Ninja"' in client.out
assert "main: {}!".format(build_type) in client.out
client.run(f"install --requires=hello/1.0@ --deploy=full_deploy -of=mydeploy {settings}")
client.run(f"install --requires=hello/1.0@ --deployer=full_deploy -of=mydeploy {settings}")
deploy_path = os.path.join(client.current_folder, "mydeploy", "full_deploy", "host", "hello", "1.0",
build_type, "x86_64")
client.run_command(f"LD_LIBRARY_PATH='{deploy_path}/lib' {deploy_path}/bin/myapp")
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_locally_build_msvc(build_type, shared, client):
client.run("create . --name=hello --version=1.0 {}".format(settings))
assert 'cmake -G "Ninja"' in client.out
assert "main: {}!".format(build_type) in client.out
client.run(f"install --requires=hello/1.0@ --deploy=full_deploy -of=mydeploy {settings}")
client.run(f"install --requires=hello/1.0@ --deployer=full_deploy -of=mydeploy {settings}")
client.run_command(fr"mydeploy\full_deploy\host\hello\1.0\{build_type}\x86_64\bin\myapp.exe")
check_exe_run(client.out, ["main", "hello"], "msvc", "19", build_type, "x86_64", cppstd="14")

Expand Down
2 changes: 1 addition & 1 deletion conans/test/integration/command/info/info_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def deploy(graph, output_folder, **kwargs):
c.save({"conanfile.py": GenConanfile().with_requires("pkg/0.1")
.with_class_attribute("license='GPL'"),
"collectlicenses.py": collectlicenses})
c.run("graph info . --deploy=collectlicenses")
c.run("graph info . --deployer=collectlicenses")
assert "conanfile.py: LICENSE : GPL!" in c.out
assert "LICENSE pkg/0.1: MIT!" in c.out
contents = c.load("licenses.txt")
Expand Down
10 changes: 5 additions & 5 deletions conans/test/integration/symlinks/symlinks_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def checker(folder):
c.run("upload * -r=default -c")
c.run("remove * -c")
c.save({}, clean_first=True)
c.run("install --requires=hello/0.1 --deploy=full_deploy")
c.run("install --requires=hello/0.1 --deployer=full_deploy")
checker(os.path.join(c.current_folder, "full_deploy", "host", "hello", "0.1"))


Expand Down Expand Up @@ -89,7 +89,7 @@ def checker(folder):
c.run("upload * -r=default -c")
c.run("remove * -c")
c.save({}, clean_first=True)
c.run("install --requires=hello/0.1 --deploy=full_deploy")
c.run("install --requires=hello/0.1 --deployer=full_deploy")
checker(os.path.join(c.current_folder, "full_deploy", "host", "hello", "0.1"))


Expand Down Expand Up @@ -126,7 +126,7 @@ def checker(folder):
c.run("upload * -r=default -c")
c.run("remove * -c")
c.save({}, clean_first=True)
c.run("install --requires=hello/0.1 --deploy=full_deploy")
c.run("install --requires=hello/0.1 --deployer=full_deploy")
checker(os.path.join(c.current_folder, "full_deploy", "host", "hello", "0.1"))


Expand Down Expand Up @@ -171,7 +171,7 @@ def checker(folder):
c.run("upload * -r=default -c")
c.run("remove * -c")
c.save({}, clean_first=True)
c.run("install --requires=hello/0.1 --deploy=full_deploy")
c.run("install --requires=hello/0.1 --deployer=full_deploy")
checker(os.path.join(c.current_folder, "full_deploy", "host", "hello", "0.1"))


Expand Down Expand Up @@ -228,7 +228,7 @@ def assert_folder_symlinks(base_folder):
client.run("remove * -c")

# Client 2 install
client2.run("install --requires=hello/0.1 --deploy=full_deploy")
client2.run("install --requires=hello/0.1 --deployer=full_deploy")
# Check package files are there
package_folder = client2.get_latest_pkg_layout(pref).package()
assert_folder_symlinks(package_folder)
Expand Down