def create_package(conanfile, source_folder, build_folder, package_folder, install_folder, output, local=False, copy_info=False): """ copies built artifacts, libs, headers, data, etc. from build_folder to package folder """ mkdir(package_folder) # Make the copy of all the patterns output.info("Generating the package") output.info("Package folder %s" % package_folder) try: package_output = ScopedOutput("%s package()" % output.scope, output) output.highlight("Calling package()") conanfile.package_folder = package_folder conanfile.source_folder = source_folder conanfile.install_folder = install_folder conanfile.build_folder = build_folder def recipe_has(attribute): return attribute in conanfile.__class__.__dict__ if source_folder != build_folder: conanfile.copy = FileCopier(source_folder, package_folder, build_folder) with conanfile_exception_formatter(str(conanfile), "package"): with tools.chdir(source_folder): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("package"): output.warn("No files copied from source folder!") conanfile.copy = FileCopier(build_folder, package_folder) with tools.chdir(build_folder): with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("build") and recipe_has("package"): output.warn("No files copied from build folder!") except Exception as e: if not local: os.chdir(build_folder) try: rmdir(package_folder) except Exception as e_rm: output.error("Unable to remove package folder %s\n%s" % (package_folder, str(e_rm))) output.warn("**** Please delete it manually ****") if isinstance(e, ConanExceptionInUserConanfileMethod): raise raise ConanException(e) _create_aux_files(install_folder, package_folder, conanfile, copy_info) output.success("Package '%s' created" % os.path.basename(package_folder))
def test_windows_case_insensitive_ps1(env): display = textwrap.dedent("""\ echo "MyVar=$env:MyVar!!" echo "MyVar1=$env:MyVar1!!" echo "MyVar2=$env:MyVar2!!" """) prevenv = { "MYVAR2": "OldValue2", } prevenv.update(dict(os.environ.copy())) with chdir(temp_folder()): env.save_ps1("test.ps1") save("display.ps1", display) cmd = "powershell.exe .\\test.ps1 ; .\\display.ps1 ; .\\deactivate_test.ps1 ; .\\display.ps1" check_command_output(cmd, prevenv)
def test_windows_case_insensitive_bat(env): display = textwrap.dedent("""\ @echo off echo MyVar=%MyVar%!! echo MyVar1=%MyVar1%!! echo MyVar2=%MyVar2%!! """) prevenv = { "MYVAR2": "OldValue2", } with chdir(temp_folder()): env.save_bat("test.bat") save("display.bat", display) cmd = "test.bat && display.bat && deactivate_test.bat && display.bat" check_command_output(cmd, prevenv)
def basic_test2(self): with chdir(self.cache.store): ref1 = ConanFileReference.loads("opencv/2.4.10@lasote/testing") root_folder = str(ref1).replace("@", "/") artifacts = ["a", "b", "c"] reg1 = "%s/%s" % (root_folder, EXPORT_FOLDER) os.makedirs(reg1) for artif_id in artifacts: build1 = "%s/%s/%s" % (root_folder, BUILD_FOLDER, artif_id) artif1 = "%s/%s/%s" % (root_folder, PACKAGES_FOLDER, artif_id) os.makedirs(build1) info = ConanInfo().loads("[settings]\n[options]") save(os.path.join(artif1, CONANINFO), info.dumps()) packages = search_packages(self.cache, ref1, "") all_artif = [_artif for _artif in sorted(packages)] self.assertEqual(all_artif, artifacts)
def test_virtualrunenv(self): client = TestClient(servers=self.servers, users={"default": [("lasote", "mypass")]}) client.run("install Pkg/0.1@lasote/testing -g virtualrunenv") with tools.chdir(client.current_folder): if platform.system() == "Windows": command = "activate_run.bat && say_hello" else: # It is not necessary to use the DYLD_LIBRARY_PATH in OSX because the activate_run.sh # will work perfectly. It is inside bash, so the loader will use DYLD_LIBRARY_PATH # values. It also works in command line with export DYLD_LIBRARY_PATH=[path] and then # running, or in the same line "$ DYLD_LIBRARY_PATH=[path] say_hello" command = "bash -c 'source activate_run.sh && say_hello'" output = check_output_runner(command) self.assertIn("Hello Tool!", output)
def _process_git_repo(repo_url, cache, output, tmp_folder, verify_ssl, args=None): output.info("Trying to clone repo: %s" % repo_url) with tools.chdir(tmp_folder): try: args = args or "" git = Git(verify_ssl=verify_ssl, output=output) git.clone(repo_url, args=args) output.info("Repo cloned!") except Exception as e: raise ConanException("Can't clone repo: %s" % str(e)) _process_folder(tmp_folder, cache, output)
def _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache, export_folder, export_source_folder, local_sources_path): """Execute the source core functionality, both for local cache and user space, in order: - Calling pre_source hook - Getting sources from SCM - Getting sources from exported folders in the local cache - Clean potential TGZ and other files in the local cache - Executing the recipe source() method - Calling post_source hook """ conanfile.source_folder = src_folder conanfile.build_folder = None conanfile.package_folder = None with tools.chdir(src_folder): try: with get_env_context_manager(conanfile): hook_manager.execute("pre_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) output = conanfile.output output.info('Configuring sources in %s' % src_folder) _run_scm(conanfile, src_folder, local_sources_path, output, cache=cache) if cache: _get_sources_from_exports(conanfile, src_folder, export_folder, export_source_folder, cache) _clean_source_folder(src_folder) with conanfile_exception_formatter(conanfile.display_name, "source"): conanfile.source() hook_manager.execute("post_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def install_custom_args_test(self): """ should install from a git repo """ folder = self._create_profile_folder() with tools.chdir(folder): self.client.runner('git init .') self.client.runner('git add .') self.client.runner('git config user.name myname') self.client.runner('git config user.email [email protected]') self.client.runner('git commit -m "mymsg"') self.client.run( 'config install "%s/.git" --args="-c init.templateDir=value"' % folder) check_path = os.path.join(folder, ".git") self._check("git, %s, True, -c init.templateDir=value" % check_path)
def case_insensitive_test(self): with chdir(self.paths.store): root_folder2 = "sdl/1.5/lasote/stable" conan_ref2 = ConanFileReference.loads("sdl/1.5@lasote/stable") os.makedirs("%s/%s" % (root_folder2, EXPORT_FOLDER)) root_folder3 = "assimp/0.14/phil/testing" conan_ref3 = ConanFileReference.loads("assimp/0.14@phil/testing") os.makedirs("%s/%s" % (root_folder3, EXPORT_FOLDER)) root_folder4 = "sdl/2.10/lasote/stable" conan_ref4 = ConanFileReference.loads("sdl/2.10@lasote/stable") os.makedirs("%s/%s" % (root_folder4, EXPORT_FOLDER)) root_folder5 = "SDL_fake/1.10/lasote/testing" conan_ref5 = ConanFileReference.loads( "SDL_fake/1.10@lasote/testing") os.makedirs("%s/%s" % (root_folder5, EXPORT_FOLDER)) # Case insensitive searches reg_conans = sorted( [str(_reg) for _reg in search_recipes(self.paths, "*")]) self.assertEqual(reg_conans, [ str(conan_ref5), str(conan_ref3), str(conan_ref2), str(conan_ref4) ]) reg_conans = sorted([ str(_reg) for _reg in search_recipes(self.paths, pattern="sdl*") ]) self.assertEqual( reg_conans, [str(conan_ref5), str(conan_ref2), str(conan_ref4)]) # Case sensitive search self.assertEqual( str( search_recipes(self.paths, pattern="SDL*", ignorecase=False)[0]), str(conan_ref5))
def scm_sources_test(self): """ Test conan_sources.tgz is deleted in server when removing 'exports_sources' and using 'scm'""" conanfile = """from conans import ConanFile class TestConan(ConanFile): name = "test" version = "1.0" """ exports_sources = """ exports_sources = "include/*" """ servers = {"upload_repo": TestServer([("*/*@*/*", "*")], [("*/*@*/*", "*")], users={"lasote": "mypass"})} client = TestClient(servers=servers, users={"upload_repo": [("lasote", "mypass")]}) client.save({"conanfile.py": conanfile + exports_sources, "include/file": "content"}) client.run("create . danimtb/testing") client.run("upload test/1.0@danimtb/testing -r upload_repo") self.assertIn("Uploading conan_sources.tgz", client.out) ref = ConanFileReference("test", "1.0", "danimtb", "testing") export_sources_path = os.path.join(servers["upload_repo"].server_store.export(ref), "conan_sources.tgz") self.assertTrue(os.path.exists(export_sources_path)) scm = """ scm = {"type": "git", "url": "auto", "revision": "auto"} """ client.save({"conanfile.py": conanfile + scm}) with chdir(client.current_folder): client.runner("git init") client.runner('git config user.email "*****@*****.**"') client.runner('git config user.name "Your Name"') client.runner("git remote add origin https://github.com/fake/fake.git") client.runner("git add .") client.runner("git commit -m \"initial commit\"") client.run("create . danimtb/testing") self.assertIn("Repo origin deduced by 'auto': https://github.com/fake/fake.git", client.out) client.run("upload test/1.0@danimtb/testing -r upload_repo") self.assertNotIn("Uploading conan_sources.tgz", client.out) export_sources_path = os.path.join(servers["upload_repo"].server_store.export(ref), "conan_sources.tgz") self.assertFalse(os.path.exists(export_sources_path))
def _run_source(conanfile, conanfile_path, hook_manager, reference, cache, get_sources_from_exports): """Execute the source core functionality, both for local cache and user space, in order: - Calling pre_source hook - Getting sources from SCM - Getting sources from exported folders in the local cache - Clean potential TGZ and other files in the local cache - Executing the recipe source() method - Calling post_source hook """ src_folder = conanfile.source_folder if hasattr(conanfile, "layout") \ else conanfile.folders.base_source mkdir(src_folder) with tools.chdir(src_folder): try: with get_env_context_manager(conanfile): hook_manager.execute("pre_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) output = conanfile.output output.info('Configuring sources in %s' % src_folder) get_sources_from_exports() if cache: # Clear the conanfile.py to avoid errors cloning git repositories. _clean_source_folder(src_folder) with conanfile_exception_formatter(conanfile.display_name, "source"): with conan_v2_property(conanfile, 'settings', "'self.settings' access in source() method is deprecated"): with conan_v2_property(conanfile, 'options', "'self.options' access in source() method is deprecated"): conanfile.source() hook_manager.execute("post_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def call_package_info(conanfile, package_folder): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [name for name, req in conanfile.requires.items() if not req.private] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None conanfile.package_info()
def _call_package_info(self, conanfile, package_folder, ref): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.name = conanfile.name conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [ name for name, req in conanfile.requires.items() if not req.private and not req.override ] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts conan_v2 = get_env(CONAN_V2_MODE_ENVVAR, False) with pythonpath(conanfile) if not conan_v2 else no_op( ): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) conanfile.package_info() if conanfile._conan_dep_cpp_info is None: try: conanfile.cpp_info._raise_incorrect_components_definition( conanfile.name, conanfile.requires) except ConanException as e: raise ConanException("%s package_info(): %s" % (str(conanfile), e)) conanfile._conan_dep_cpp_info = DepCppInfo( conanfile.cpp_info) self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def _run_method(conanfile, method, origin_folder, destination_folder, output): export_method = getattr(conanfile, method, None) if export_method: if not callable(export_method): raise ConanException("conanfile '%s' must be a method" % method) output.highlight("Calling %s()" % method) copier = FileCopier([origin_folder], destination_folder) conanfile.copy = copier default_options = conanfile.default_options try: # TODO: Poor man attribute control access. Convert to nice decorator conanfile.default_options = None with chdir(origin_folder): with conanfile_exception_formatter(str(conanfile), method): export_method() finally: conanfile.default_options = default_options export_method_output = ScopedOutput( "%s %s() method" % (output.scope, method), output) copier.report(export_method_output)
def _call_package_info(conanfile, package_folder): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [name for name, req in conanfile.requires.items() if not req.private] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts with pythonpath(conanfile): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None conanfile.package_info()
def _call_package_info(self, conanfile, package_folder, ref): conanfile.cpp_info = CppInfo(conanfile.name, package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [ name for name, req in conanfile.requires.items() if not req.private and not req.override ] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts # Minimal pythonpath, not the whole context, make it 50% slower # FIXME Conan 2.0, Remove old ways of reusing python code with pythonpath(conanfile): with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.layout.set_base_package_folder(package_folder) conanfile.layout.set_base_source_folder(None) conanfile.layout.set_base_build_folder(None) conanfile.layout.set_base_install_folder(None) self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) conanfile.package_info() if conanfile._conan_dep_cpp_info is None: try: conanfile.cpp_info._raise_incorrect_components_definition( conanfile.name, conanfile.requires) except ConanException as e: raise ConanException("%s package_info(): %s" % (str(conanfile), e)) conanfile._conan_dep_cpp_info = DepCppInfo( conanfile.cpp_info) self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache, get_sources_from_exports): """Execute the source core functionality, both for local cache and user space, in order: - Calling pre_source hook - Getting sources from SCM - Getting sources from exported folders in the local cache - Clean potential TGZ and other files in the local cache - Executing the recipe source() method - Calling post_source hook """ conanfile.source_folder = src_folder conanfile.build_folder = None conanfile.package_folder = None with tools.chdir(src_folder): try: with get_env_context_manager(conanfile): hook_manager.execute("pre_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) output = conanfile.output output.info('Configuring sources in %s' % src_folder) get_sources_from_exports() if cache: _clean_source_folder(src_folder) # TODO: Why is it needed in cache? with conanfile_exception_formatter(conanfile.display_name, "source"): with conan_v2_property(conanfile, 'settings', "'self.settings' access in source() method is deprecated"): with conan_v2_property(conanfile, 'options', "'self.options' access in source() method is deprecated"): conanfile.source() hook_manager.execute("post_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def test_env_files_sh(env, prevenv): display = textwrap.dedent("""\ echo MyVar=$MyVar!! echo MyVar1=$MyVar1!! echo MyVar2=$MyVar2!! echo MyVar3=$MyVar3!! echo MyVar4=$MyVar4!! echo MyVar5=$MyVar5!! echo MyVar6=$MyVar6!! echo MyPath1=$MyPath1!! echo MyPath2=$MyPath2!! echo MyPath3=$MyPath3!! echo MyPath4=$MyPath4!! """) with chdir(temp_folder()): env = env.vars(ConanFileMock()) env.save_sh("test.sh") save("display.sh", display) os.chmod("display.sh", 0o777) cmd = '. ./test.sh && ./display.sh && . ./deactivate_test.sh && ./display.sh' check_env_files_output(cmd, prevenv)
def test_env_files_bat(env, prevenv): display = textwrap.dedent("""\ @echo off echo MyVar=%MyVar%!! echo MyVar1=%MyVar1%!! echo MyVar2=%MyVar2%!! echo MyVar3=%MyVar3%!! echo MyVar4=%MyVar4%!! echo MyVar5=%MyVar5%!! echo MyVar6=%MyVar6%!! echo MyPath1=%MyPath1%!! echo MyPath2=%MyPath2%!! echo MyPath3=%MyPath3%!! echo MyPath4=%MyPath4%!! """) with chdir(temp_folder()): env = env.vars(ConanFileMock()) env.save_bat("test.bat") save("display.bat", display) cmd = "test.bat && display.bat && deactivate_test.bat && display.bat" check_env_files_output(cmd, prevenv)
def run_deploy(conanfile, install_folder): deploy_output = ScopedOutput("%s deploy()" % conanfile.display_name, conanfile.output) file_importer = _FileImporter(conanfile, install_folder) package_copied = set() # This is necessary to capture FileCopier full destination paths # Maybe could be improved in FileCopier def file_copier(*args, **kwargs): file_copy = FileCopier(conanfile.package_folder, install_folder) copied = file_copy(*args, **kwargs) _make_files_writable(copied) package_copied.update(copied) conanfile.copy_deps = file_importer conanfile.copy = file_copier conanfile.install_folder = install_folder with get_env_context_manager(conanfile): with tools.chdir(install_folder): conanfile.deploy() copied_files = file_importer.copied_files copied_files.update(package_copied) _report_save_manifest(copied_files, deploy_output, install_folder, "deploy_manifest.txt")
def test_env_files_ps1(env, prevenv): prevenv.update(dict(os.environ.copy())) display = textwrap.dedent("""\ echo "MyVar=$env:MyVar!!" echo "MyVar1=$env:MyVar1!!" echo "MyVar2=$env:MyVar2!!" echo "MyVar3=$env:MyVar3!!" echo "MyVar4=$env:MyVar4!!" echo "MyVar5=$env:MyVar5!!" echo "MyVar6=$env:MyVar6!!" echo "MyPath1=$env:MyPath1!!" echo "MyPath2=$env:MyPath2!!" echo "MyPath3=$env:MyPath3!!" echo "MyPath4=$env:MyPath4!!" """) with chdir(temp_folder()): env = env.vars(ConanFileMock()) env.save_ps1("test.ps1") save("display.ps1", display) cmd = "powershell.exe .\\test.ps1 ; .\\display.ps1 ; .\\deactivate_test.ps1 ; .\\display.ps1" check_env_files_output(cmd, prevenv)
def _call_package_info(self, conanfile, package_folder, ref): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [name for name, req in conanfile.requires.items() if not req.private] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts with pythonpath(conanfile): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) conanfile.package_info() self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def curdir_test(self): tmp_folder = temp_folder() conanfile = """from conans import ConanFile class Pkg(ConanFile): name = "lib" version = "1.0" """ tools.save(os.path.join(tmp_folder, "conanfile.py"), conanfile) with tools.chdir(tmp_folder): # Needed to not write in the real computer cache with tools.environment_append({"CONAN_USER_HOME": tmp_folder}): api, _, _ = ConanAPIV1.factory() api.create(".", name="lib", version="1.0", user="******", channel="channel") self.assertEqual(tmp_folder, os.getcwd()) api.create(".", name="lib", version="1.0", user="******", channel="channel2") self.assertEqual(tmp_folder, os.getcwd())
def create_local_svn_checkout(files, repo_url, rel_project_path=None, commit_msg='default commit message', delete_checkout=True, folder=None): tmp_dir = folder or temp_folder() try: rel_project_path = rel_project_path or str(uuid.uuid4()) # Do not use SVN class as it is what we will be testing subprocess.check_output('svn co "{url}" "{path}"'.format(url=repo_url, path=tmp_dir), shell=True) tmp_project_dir = os.path.join(tmp_dir, rel_project_path) mkdir(tmp_project_dir) save_files(tmp_project_dir, files) with chdir(tmp_project_dir): subprocess.check_output("svn add .", shell=True) subprocess.check_output('svn commit -m "{}"'.format(commit_msg), shell=True) if SVN.get_version() >= SVN.API_CHANGE_VERSION: rev = check_output_runner( "svn info --show-item revision").strip() else: import xml.etree.ElementTree as ET output = check_output_runner("svn info --xml").strip() root = ET.fromstring(output) rev = root.findall("./entry")[0].get("revision") project_url = repo_url + "/" + quote( rel_project_path.replace("\\", "/")) return project_url, rev finally: if delete_checkout: shutil.rmtree(tmp_dir, ignore_errors=False, onerror=try_remove_readonly)
def _run_app(self, client, arch, build_type, shared=None): if build_type == "Release" and shared: configuration = "ReleaseShared" else: configuration = build_type if arch == "x86": command_str = "%s\\MyApp.exe" % configuration else: command_str = "x64\\%s\\MyApp.exe" % configuration # To run the app without VS IDE, we need to copy the .exe to the DLLs folder new_cmd = "conan\\%s\\%s\\MyApp.exe" % (arch, configuration) with chdir(client.current_folder): mkdir(os.path.dirname(new_cmd)) shutil.copy(command_str, new_cmd) client.run_command(new_cmd) if arch == "x86": self.assertIn("main _M_IX86 defined", client.out) else: self.assertIn("main _M_X64 defined", client.out) self.assertIn("Hello World %s" % build_type, client.out) self.assertIn("main: %s!" % build_type, client.out) self.assertIn("DEFINITIONS_BOTH: True", client.out) self.assertIn("DEFINITIONS_CONFIG: %s" % build_type, client.out)
def create_package(conanfile, pkg_id, source_folder, build_folder, package_folder, install_folder, output, hook_manager, conanfile_path, reference, local=False, copy_info=False): """ copies built artifacts, libs, headers, data, etc. from build_folder to package folder """ mkdir(package_folder) # Make the copy of all the patterns output.info("Generating the package") output.info("Package folder %s" % package_folder) try: conanfile.package_folder = package_folder conanfile.source_folder = source_folder conanfile.install_folder = install_folder conanfile.build_folder = build_folder hook_manager.execute("pre_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference, package_id=pkg_id) package_output = ScopedOutput("%s package()" % output.scope, output) output.highlight("Calling package()") def recipe_has(attribute): return attribute in conanfile.__class__.__dict__ if source_folder != build_folder: conanfile.copy = FileCopier(source_folder, package_folder, build_folder) with conanfile_exception_formatter(str(conanfile), "package"): with tools.chdir(source_folder): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("package"): output.warn("No files copied from source folder!") conanfile.copy = FileCopier(build_folder, package_folder) with tools.chdir(build_folder): with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("build") and recipe_has("package"): output.warn("No files copied from build folder!") except Exception as e: if not local: os.chdir(build_folder) try: rmdir(package_folder) except Exception as e_rm: output.error("Unable to remove package folder %s\n%s" % (package_folder, str(e_rm))) output.warn("**** Please delete it manually ****") if isinstance(e, ConanExceptionInUserConanfileMethod): raise raise ConanException(e) _create_aux_files(install_folder, package_folder, conanfile, copy_info) pkg_id = pkg_id or os.path.basename(package_folder) output.success("Package '%s' created" % pkg_id) hook_manager.execute("post_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference, package_id=pkg_id)
def test_shared_in_current_directory(self): """ - There is a package building a shared library - There is a consumer project importing the shared library (and the executable) - The consumer tries to execute the imported shared library and executable in the same directory, and it fails in Linux, but works on OSX and WIndows. - Then I move the shared library to a different directory, and it fails, I'm making sure that there is no harcoded rpaths messing. - Finally I use the virtualrunenvironment that declares de LD_LIBRARY_PATH, PATH and DYLD_LIBRARY_PATH to run the executable, and.. magic! it's running agains the shared in the local cache. """ conanfile = """ from conans import ConanFile, CMake, tools class LibConan(ConanFile): name = "lib" version = "1.0" settings = "os", "compiler", "build_type", "arch" options = {"shared": [True, False]} default_options = "shared=True" generators = "cmake" exports_sources = "*" def build(self): cmake = CMake(self) self.run('cmake %s' % cmake.command_line) self.run("cmake --build . %s" % cmake.build_config) def package(self): self.copy("*.h", dst="include", src="hello") self.copy("*.lib", dst="lib", keep_path=False) self.copy("*.dll", dst="bin", keep_path=False) self.copy("*.so", dst="lib", keep_path=False) self.copy("*.dylib", dst="lib", keep_path=False) self.copy("*main*", dst="bin", keep_path=False) """ cmakelists = """ set(CMAKE_CXX_COMPILER_WORKS 1) set(CMAKE_CXX_ABI_COMPILED 1) project(mytest) SET(CMAKE_SKIP_RPATH 1) ADD_LIBRARY(hello SHARED hello.c) ADD_EXECUTABLE(main main.c) TARGET_LINK_LIBRARIES(main hello) """ hello_h = """#pragma once #ifdef WIN32 #define HELLO_EXPORT __declspec(dllexport) #else #define HELLO_EXPORT #endif HELLO_EXPORT void hello(); """ client = TestClient() files = {CONANFILE: conanfile, "CMakeLists.txt": cmakelists, "hello.c": '#include "hello.h"\nvoid hello(){\nreturn;}', "hello.h": hello_h, "main.c": '#include "hello.h"\nint main(){\nhello();\nreturn 0;\n}'} client.save(files) client.run("export . conan/stable") client.run("install lib/1.0@conan/stable -o lib:shared=True --build missing") client.save({"conanfile.txt": ''' [requires] lib/1.0@conan/stable [generators] virtualrunenv [imports] bin, * -> ./bin lib, * -> ./bin '''}, clean_first=True) client.run("install .") # Break possible rpaths built in the exe with absolute paths os.rename(os.path.join(client.current_folder, "bin"), os.path.join(client.current_folder, "bin2")) with tools.chdir(os.path.join(client.current_folder, "bin2")): if platform.system() == "Windows": self.assertEqual(os.system("main.exe"), 0) elif platform.system() == "Darwin": self.assertEqual(os.system("./main"), 0) else: self.assertNotEqual(os.system("./main"), 0) self.assertEqual(os.system("LD_LIBRARY_PATH=$(pwd) ./main"), 0) self.assertEqual(os.system("LD_LIBRARY_PATH=. ./main"), 0) # If we move the shared library it won't work, at least we use the virtualrunenv os.mkdir(os.path.join(client.current_folder, "bin2", "subdir")) name = {"Darwin": "libhello.dylib", "Windows": "hello.dll"}.get(platform.system(), "libhello.so") os.rename(os.path.join(client.current_folder, "bin2", name), os.path.join(client.current_folder, "bin2", "subdir", name)) if platform.system() == "Windows": self.assertNotEqual(os.system("main.exe"), 0) elif platform.system() == "Darwin": self.assertNotEqual(os.system("./main"), 0) else: self.assertNotEqual(os.system("LD_LIBRARY_PATH=$(pwd) ./main"), 0) # Will use the shared from the local cache if platform.system() != "Windows": command = "bash -c 'source ../activate_run.sh && ./main'" else: command = "cd .. && activate_run.bat && cd bin2 && main.exe" self.assertEqual(os.system(command), 0)
def _call_package_info(self, conanfile, package_folder, ref, is_editable): conanfile.cpp_info = CppInfo(conanfile.name, package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [ name for name, req in conanfile.requires.items() if not req.private and not req.override ] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts # Minimal pythonpath, not the whole context, make it 50% slower # FIXME Conan 2.0, Remove old ways of reusing python code with pythonpath(conanfile): with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) if hasattr(conanfile, "layout"): # Old cpp info without defaults (the defaults are in the new one) conanfile.cpp_info = CppInfo( conanfile.name, package_folder, default_values=CppInfoDefaultValues()) if not is_editable: conanfile.cpp.package.set_relative_base_folder( conanfile.package_folder) # Copy the infos.package into the old cppinfo fill_old_cppinfo(conanfile.cpp.package, conanfile.cpp_info) else: conanfile.cpp_info.filter_empty = False conanfile.package_info() if hasattr(conanfile, "layout") and is_editable: # Adjust the folders of the layout to consolidate the rootfolder of the # cppinfos inside # convert directory entries to be relative to the declared folders.build conanfile.cpp.build.set_relative_base_folder( conanfile.build_folder) # convert directory entries to be relative to the declared folders.source conanfile.cpp.source.set_relative_base_folder( conanfile.source_folder) full_editable_cppinfo = NewCppInfo() full_editable_cppinfo.merge(conanfile.cpp.source) full_editable_cppinfo.merge(conanfile.cpp.build) # Paste the editable cpp_info but prioritizing it, only if a # variable is not declared at build/source, the package will keep the value fill_old_cppinfo(full_editable_cppinfo, conanfile.cpp_info) if conanfile._conan_dep_cpp_info is None: try: if not is_editable and not hasattr( conanfile, "layout"): # FIXME: The default for the cppinfo from build are not the same # so this check fails when editable # FIXME: Remove when new cppinfo model. If using the layout method # the cppinfo object is filled from self.cpp.package new # model and we cannot check if the defaults have been modified # because it doesn't exist in the new model where the defaults # for the components are always empty conanfile.cpp_info._raise_incorrect_components_definition( conanfile.name, conanfile.requires) except ConanException as e: raise ConanException("%s package_info(): %s" % (str(conanfile), e)) conanfile._conan_dep_cpp_info = DepCppInfo( conanfile.cpp_info) self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def call_package_info(conanfile, package_folder): # Once the node is build, execute package info, so it has access to the # package folder and artifacts with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_info()
def test_shared_run_environment(self): servers = {"default": TestServer()} client = TestClient(servers=servers, users={"default": [("lasote", "mypass")]}) cmake = """set(CMAKE_CXX_COMPILER_WORKS 1) set(CMAKE_CXX_ABI_COMPILED 1) project(MyHello CXX) cmake_minimum_required(VERSION 2.8.12) add_library(hello SHARED hello.cpp) add_executable(say_hello main.cpp) target_link_libraries(say_hello hello)""" hello_h = """#ifdef WIN32 #define HELLO_EXPORT __declspec(dllexport) #else #define HELLO_EXPORT #endif HELLO_EXPORT void hello(); """ hello_cpp = r"""#include "hello.h" #include <iostream> void hello(){ std::cout<<"Hello Tool!\n"; } """ main = """#include "hello.h" int main(){ hello(); } """ conanfile = """from conans import ConanFile, CMake class Pkg(ConanFile): exports_sources = "*" def build(self): cmake = CMake(self) cmake.configure() cmake.build() def package(self): self.copy("*say_hello.exe", dst="bin", keep_path=False) self.copy("*say_hello", dst="bin", keep_path=False) self.copy(pattern="*.dll", dst="bin", keep_path=False) self.copy(pattern="*.dylib", dst="lib", keep_path=False) self.copy(pattern="*.so", dst="lib", keep_path=False) """ client.save({ "conanfile.py": conanfile, "CMakeLists.txt": cmake, "main.cpp": main, "hello.cpp": hello_cpp, "hello.h": hello_h }) client.run("create . Pkg/0.1@lasote/testing") client.run("upload Pkg* --all --confirm") client.run('remove "*" -f') client.run("search") self.assertIn("There are no packages", client.out) # MAKE SURE WE USE ANOTHER CLIENT, with another USER HOME PATH client2 = TestClient(servers=servers, users={"default": [("lasote", "mypass")]}) self.assertNotEqual(client2.base_folder, client.base_folder) reuse = '''from conans import ConanFile class HelloConan(ConanFile): requires = "Pkg/0.1@lasote/testing" def build(self): self.run("say_hello", run_environment=True) ''' client2.save({"conanfile.py": reuse}, clean_first=True) client2.run("install .") client2.run("build .") self.assertIn("Hello Tool!", client2.out) if platform.system() != "Darwin": # This test is excluded from OSX, because of the SIP protection. CMake helper will # launch a subprocess with shell=True, which CLEANS the DYLD_LIBRARY_PATH. Injecting its # value via run_environment=True doesn't work, because it prepends its value to: # command = "cd [folder] && cmake [cmd]" => "DYLD_LIBRARY_PATH=[path] cd [folder] && cmake [cmd]" # and then only applies to the change directory "cd" # If CMake binary is in user folder, it is not under SIP, and it can work. For cmake installed in # system folders, then no possible form of "DYLD_LIBRARY_PATH=[folders] cmake" can work reuse = '''from conans import ConanFile, CMake, tools class HelloConan(ConanFile): exports = "CMakeLists.txt" requires = "Pkg/0.1@lasote/testing" def build(self): with tools.run_environment(self): cmake = CMake(self) cmake.configure() cmake.build() ''' cmake = """set(CMAKE_CXX_COMPILER_WORKS 1) set(CMAKE_CXX_ABI_COMPILED 1) project(MyHello CXX) cmake_minimum_required(VERSION 2.8.12) execute_process(COMMAND say_hello) """ client2.save({ "conanfile.py": reuse, "CMakeLists.txt": cmake }, clean_first=True) client2.run("install . -g virtualrunenv") client2.run("build .") self.assertIn("Hello Tool!", client2.out) else: client2.run("install . -g virtualrunenv") with tools.chdir(client2.current_folder): if platform.system() == "Windows": command = "activate_run.bat && say_hello" else: # It is not necessary to use the DYLD_LIBRARY_PATH in OSX because the activate_run.sh # will work perfectly. It is inside the bash, so the loader will use DYLD_LIBRARY_PATH # values. It also works in command line with export DYLD_LIBRARY_PATH=[path] and then # running, or in the same line "$ DYLD_LIBRARY_PATH=[path] say_hello" command = "bash -c 'source activate_run.sh && say_hello'" output = subprocess.check_output(command, shell=True) self.assertIn("Hello Tool!", str(output))
def cmd_build(app, conanfile_path, base_path, source_folder, build_folder, package_folder, install_folder, test=False, should_configure=True, should_build=True, should_install=True, should_test=True): """ Call to build() method saved on the conanfile.py param conanfile_path: path to a conanfile.py """ logger.debug("BUILD: folder '%s'" % build_folder) logger.debug("BUILD: Conanfile at '%s'" % conanfile_path) try: conan_file = app.graph_manager.load_consumer_conanfile( conanfile_path, install_folder, deps_info_required=True, test=test) except NotFoundException: # TODO: Auto generate conanfile from requirements file raise ConanException("'%s' file is needed for build.\n" "Create a '%s' and move manually the " "requirements and generators from '%s' file" % (CONANFILE, CONANFILE, CONANFILE_TXT)) if test: try: conan_file.requires.add_ref(test) except ConanException: pass conan_file.should_configure = should_configure conan_file.should_build = should_build conan_file.should_install = should_install conan_file.should_test = should_test try: # FIXME: Conan 2.0 all these build_folder, source_folder will disappear # Only base_path and conanfile_path will remain if hasattr(conan_file, "layout"): conanfile_folder = os.path.dirname(conanfile_path) conan_file.folders.set_base_build(conanfile_folder) conan_file.folders.set_base_source(conanfile_folder) conan_file.folders.set_base_package(conanfile_folder) conan_file.folders.set_base_generators(conanfile_folder) conan_file.folders.set_base_install(conanfile_folder) else: conan_file.folders.set_base_build(build_folder) conan_file.folders.set_base_source(source_folder) conan_file.folders.set_base_package(package_folder) conan_file.folders.set_base_generators(base_path) conan_file.folders.set_base_install(install_folder) mkdir(conan_file.build_folder) with chdir(conan_file.build_folder): run_build_method(conan_file, app.hook_manager, conanfile_path=conanfile_path) if test: with get_env_context_manager(conan_file): conan_file.output.highlight("Running test()") with conanfile_exception_formatter(str(conan_file), "test"): with chdir(conan_file.build_folder): conan_file.test() except ConanException: raise # Raise but not let to reach the Exception except (not print traceback) except Exception: import traceback trace = traceback.format_exc().split('\n') raise ConanException("Unable to build it successfully\n%s" % '\n'.join(trace[3:]))
def complete_creation_reuse_test(self): client = TestClient(path_with_spaces=False) client.run("new myhello/1.0.0 --sources") conanfile_path = os.path.join(client.current_folder, "conanfile.py") replace_in_file(conanfile_path, "{\"shared\": [True, False]}", "{\"shared\": [True, False], \"fPIC\": [True, False]}", output=client.out) replace_in_file(conanfile_path, "\"shared=False\"", "\"shared=False\", \"fPIC=True\"", output=client.out) client.run("create . danimtb/testing") hellowrapper_include = """ #pragma once void hellowrapper(); """ hellowrapper_impl = """ #include "hello.h" #include "hellowrapper.h" void hellowrapper(){ hello(); } """ makefile = """ include conanbuildinfo.mak #---------------------------------------- # Make variables for a sample App #---------------------------------------- INCLUDE_DIRS = \ ./include CXX_SRCS = \ src/hellowrapper.cpp CXX_OBJ_FILES = \ hellowrapper.o STATIC_LIB_FILENAME = \ libhellowrapper.a SHARED_LIB_FILENAME = \ libhellowrapper.so CXXFLAGS += \ -fPIC #---------------------------------------- # Prepare flags from variables #---------------------------------------- CFLAGS += $(CONAN_CFLAGS) CXXFLAGS += $(CONAN_CXXFLAGS) CPPFLAGS += $(addprefix -I, $(INCLUDE_DIRS) $(CONAN_INCLUDE_DIRS)) CPPFLAGS += $(addprefix -D, $(CONAN_DEFINES)) LDFLAGS += $(addprefix -L, $(CONAN_LIB_DIRS)) LDLIBS += $(addprefix -l, $(CONAN_LIBS)) SHAREDLINKFLAGS += $(CONAN_SHAREDLINKFLAGS) #---------------------------------------- # Make Commands #---------------------------------------- COMPILE_CXX_COMMAND ?= \ g++ -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@ CREATE_SHARED_LIB_COMMAND ?= \ g++ -shared $(CXX_OBJ_FILES) \ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) $(SHAREDLINKFLAGS) \ -o $(SHARED_LIB_FILENAME) CREATE_STATIC_LIB_COMMAND ?= \ ar rcs $(STATIC_LIB_FILENAME) $(CXX_OBJ_FILES) #---------------------------------------- # Make Rules #---------------------------------------- .PHONY : static shared static : $(STATIC_LIB_FILENAME) shared : $(SHARED_LIB_FILENAME) $(SHARED_LIB_FILENAME) : $(CXX_OBJ_FILES) $(CREATE_SHARED_LIB_COMMAND) $(STATIC_LIB_FILENAME) : $(CXX_OBJ_FILES) $(CREATE_STATIC_LIB_COMMAND) $(CXX_OBJ_FILES) : $(CXX_SRCS) $(COMPILE_CXX_COMMAND) """ conanfile = """ from conans import ConanFile class HelloWrapper(ConanFile): name = "hellowrapper" version = "1.0" settings = "os", "compiler", "build_type", "arch" requires = "myhello/1.0.0@danimtb/testing" generators = "make" exports_sources = "include/hellowrapper.h", "src/hellowrapper.cpp", "Makefile" options = {"shared": [True, False]} default_options = {"shared": False} def build(self): make_command = "make shared" if self.options.shared else "make static" self.run(make_command) def package(self): self.copy("*.h", dst="include", src="include") self.copy("*.so", dst="lib", keep_path=False) self.copy("*.a", dst="lib", keep_path=False) def package_info(self): self.cpp_info.libs = ["hellowrapper"] """ client.save( { "include/hellowrapper.h": hellowrapper_include, "src/hellowrapper.cpp": hellowrapper_impl, "Makefile": makefile, "conanfile.py": conanfile }, clean_first=True) client.run("create . danimtb/testing") # Test also shared client.run("create . danimtb/testing -o hellowrapper:shared=True") main = """ #include "hellowrapper.h" int main() { hellowrapper(); return 0; } """ makefile = """ include conanbuildinfo.mak #---------------------------------------- # Make variables for a sample App #---------------------------------------- CXX_SRCS = \ src/main.cpp CXX_OBJ_FILES = \ main.o EXE_FILENAME = \ main CXXFLAGS += \ -fPIC EXELINKFLAGS += \ -fPIE #---------------------------------------- # Prepare flags from variables #---------------------------------------- CFLAGS += $(CONAN_CFLAGS) CXXFLAGS += $(CONAN_CXXFLAGS) CPPFLAGS += $(addprefix -I, $(CONAN_INCLUDE_DIRS)) CPPFLAGS += $(addprefix -D, $(CONAN_DEFINES)) LDFLAGS += $(addprefix -L, $(CONAN_LIB_DIRS)) LDLIBS += $(addprefix -l, $(CONAN_LIBS)) EXELINKFLAGS += $(CONAN_EXELINKFLAGS) #---------------------------------------- # Make Commands #---------------------------------------- COMPILE_CXX_COMMAND ?= \ g++ -c $(CPPFLAGS) $(CXXFLAGS) $< -o $@ CREATE_EXE_COMMAND ?= \ g++ $(CXX_OBJ_FILES) \ $(CXXFLAGS) $(LDFLAGS) $(LDLIBS) $(EXELINKFLAGS) \ -o $(EXE_FILENAME) #---------------------------------------- # Make Rules #---------------------------------------- .PHONY : exe exe : $(EXE_FILENAME) $(EXE_FILENAME) : $(CXX_OBJ_FILES) $(CREATE_EXE_COMMAND) $(CXX_OBJ_FILES) : $(CXX_SRCS) $(COMPILE_CXX_COMMAND) """ conanfile_txt = """ [requires] hellowrapper/1.0@danimtb/testing [generators] make """ client.save( { "src/main.cpp": main, "Makefile": makefile, "conanfile.txt": conanfile_txt }, clean_first=True) with chdir(client.current_folder): client.run("install .") client.runner("make exe") client.runner("./main") self.assertIn("Hello World Release!", client.out) # Test it also builds with shared lib client.run("install . -o hellowrapper:shared=True") client.runner("rm main main.o") client.runner("make exe") client.runner("ldd main") self.assertIn("libhellowrapper.so", client.out)