Example #1
0
def test_git_clone_with_source_layout():
    client = TestClient()
    repo = temp_folder()
    conanfile = textwrap.dedent("""
           import os
           from conans import ConanFile
           class Pkg(ConanFile):
               exports_sources = "*.txt"

               def layout(self):
                   self.folders.source = "src"

               def source(self):
                   self.run('git clone "{}" .')
       """).format(repo.replace("\\", "/"))

    client.save({"conanfile.py": conanfile, "myfile.txt": "My file is copied"})
    with client.chdir(repo):
        client.save({"cloned.txt": "foo"}, repo)
        client.init_git_repo()

    client.run("create . hello/1.0@")
    sf = client.cache.package_layout(
        ConanFileReference.loads("hello/1.0@")).source()
    assert os.path.exists(os.path.join(sf, "myfile.txt"))
    # The conanfile is cleared from the root before cloning
    assert not os.path.exists(os.path.join(sf, "conanfile.py"))
    assert not os.path.exists(os.path.join(sf, "cloned.txt"))

    assert os.path.exists(os.path.join(sf, "src", "cloned.txt"))
    assert not os.path.exists(os.path.join(sf, "src", "myfile.txt"))
Example #2
0
    def test_reuse_customize_scm(self):
        client = TestClient()
        conanfile = textwrap.dedent("""
            from conans import ConanFile
            class SomeBase(object):
                base_repo = "somerepo"
                scm = {"type" : "git",
                       "url" : base_repo,
                       "revision" : "auto"}

            class MyConanfileBase(SomeBase, ConanFile):
                pass
            """)
        client.init_git_repo({"conanfile.py": conanfile}, branch="my_release")
        client.run("export . base/1.1@user/testing")
        client.run("get base/1.1@user/testing")
        self.assertIn('"url": "somerepo"', client.out)

        reuse = textwrap.dedent("""
            from conans import ConanFile
            class PkgTest(ConanFile):
                base_repo = "other_repo"
                python_requires = "base/1.1@user/testing"
                python_requires_extend = "base.SomeBase"
                def init(self):
                    self.scm["url"] = self.base_repo
            """)
        client.save({"conanfile.py": reuse})
        client.run("export . Pkg/0.1@user/testing")
        client.run("get Pkg/0.1@user/testing")
        self.assertNotIn("scm = base.scm", client.out)
        self.assertIn('scm = {"revision":', client.out)
        self.assertIn('"type": "git",', client.out)
        self.assertIn('"url": "other_repo"', client.out)
Example #3
0
    def test_reuse_scm_multiple_conandata(self):
        # https://github.com/conan-io/conan/issues/7236
        # This only works when using conandata.yml, conanfile.py replace is broken
        client = TestClient()
        conanfile = textwrap.dedent("""
            from conans import ConanFile
            class SomeBase(object):
                scm = {"type" : "git",
                       "url" : "remote1",
                       "revision" : "auto"}

            class MyConanfileBase(SomeBase, ConanFile):
                pass
            """)
        base_rev = client.init_git_repo({"conanfile.py": conanfile},
                                        branch="my_release",
                                        folder="base")
        client.run("config set general.scm_to_conandata=1")
        client.run("export base base/1.1@user/testing")

        reuse = textwrap.dedent("""
            from conans import ConanFile
            class PkgTest(ConanFile):
                name = "%s"
                python_requires = "base/1.1@user/testing"
                python_requires_extend = "base.SomeBase"
            """)
        reuse1_rev = client.init_git_repo({"conanfile.py": reuse % "reuse1"},
                                          branch="release",
                                          folder="reuse1")
        reuse2_rev = client.init_git_repo({"conanfile.py": reuse % "reuse2"},
                                          branch="release",
                                          folder="reuse2")
        client.run("export reuse1 reuse1/1.1@user/testing")
        client.run("export reuse2 reuse2/1.1@user/testing")

        client.run("inspect base/1.1@user/testing -a=scm --json=base.json")
        base_json = json.loads(client.load("base.json"))
        client.run("inspect reuse1/1.1@user/testing -a=scm --json=reuse1.json")
        reuse1_json = json.loads(client.load("reuse1.json"))
        client.run("inspect reuse2/1.1@user/testing -a=scm --json=reuse2.json")
        reuse2_json = json.loads(client.load("reuse2.json"))
        self.assertEqual(base_json["scm"]["revision"], base_rev)
        self.assertEqual(reuse1_json["scm"]["revision"], reuse1_rev)
        self.assertEqual(reuse2_json["scm"]["revision"], reuse2_rev)
        self.assertNotEqual(base_rev, reuse1_rev)
        self.assertNotEqual(base_rev, reuse2_rev)
        self.assertNotEqual(reuse2_rev, reuse1_rev)
Example #4
0
    def test_empty_conandata(self):
        # https://github.com/conan-io/conan/issues/8209
        conanfile = textwrap.dedent("""
            from conans import ConanFile

            class Recipe(ConanFile):
                scm = {"type": "git", "url": "auto", "revision": "auto"}
            """)
        t = TestClient()
        commit = t.init_git_repo({
            'conanfile.py': conanfile,
            'conandata.yml': ""
        })
        t.run_command('git remote add origin https://myrepo.com.git')
        t.run("config set general.scm_to_conandata=1")
        t.run("export . name/version@")

        # Check exported files
        package_layout = t.cache.package_layout(self.ref)
        exported_conanfile = load(package_layout.conanfile())
        self.assertEqual(exported_conanfile, conanfile)
        exported_conandata = load(
            os.path.join(package_layout.export(), DATA_YML))
        conan_data = yaml.safe_load(exported_conandata)
        self.assertDictEqual(conan_data['.conan']['scm'], {
            "type": "git",
            "url": 'https://myrepo.com.git',
            "revision": commit
        })
Example #5
0
    def test_auto_is_replaced(self):
        conanfile = textwrap.dedent("""
            import os
            from conans import ConanFile

            class Recipe(ConanFile):
                scm = {"type": "git", "url": "auto", "revision": "auto"}
        """)
        t = TestClient()
        commit = t.init_git_repo({'conanfile.py': conanfile})
        t.run_command('git remote add origin https://myrepo.com.git')
        t.run("config set general.scm_to_conandata=1")
        t.run("export . name/version@")

        # Check exported files
        package_layout = t.cache.package_layout(self.ref)
        exported_conanfile = load(package_layout.conanfile())
        self.assertEqual(exported_conanfile, conanfile)
        exported_conandata = load(
            os.path.join(package_layout.export(), DATA_YML))
        conan_data = yaml.safe_load(exported_conandata)
        self.assertDictEqual(conan_data['.conan']['scm'], {
            "type": "git",
            "url": 'https://myrepo.com.git',
            "revision": commit
        })

        # Check the recipe gets the proper values
        t.run("inspect name/version@ -a scm")
        self.assertIn("revision: {}".format(commit), t.out)
        self.assertIn("type: git", t.out)
        self.assertIn("url: https://myrepo.com.git", t.out)
Example #6
0
    def test_delegated_python_code(self):
        client = TestClient()
        code_file = textwrap.dedent("""
            from conans.tools import Git
            from conans import ConanFile

            def get_commit(repo_path):
                git = Git(repo_path)
                return git.get_commit()

            class MyLib(ConanFile):
                pass
            """)
        client.save({"conanfile.py": code_file})
        client.run("export . tool/0.1@user/testing")

        conanfile = textwrap.dedent("""
            import os
            from conans import ConanFile, python_requires
            from conans.tools import load
            tool = python_requires("tool/0.1@user/testing")

            class MyLib(ConanFile):
                scm = {'type': 'git', 'url': '%s',
                       'revision': tool.get_commit(os.path.dirname(__file__))}
                def build(self):
                    self.output.info("File: {}".format(load("file.txt")))
            """ % client.current_folder.replace("\\", "/"))

        commit = client.init_git_repo({"conanfile.py": conanfile, "file.txt": "hello!"})
        client.run("export . pkg/0.1@user/channel")
        ref = ConanFileReference.loads("pkg/0.1@user/channel")
        exported_conanfile = client.cache.package_layout(ref).conanfile()
        content = load(exported_conanfile)
        self.assertIn(commit, content)
Example #7
0
    def test_revision_mode_scm(self):
        t = TestClient()
        commit = t.init_git_repo({'conanfile.py': self.conanfile.format(revision_mode="scm")})

        ref = ConanFileReference.loads("name/version@user/channel")
        t.run("export . {}".format(ref))

        meta = t.cache.package_layout(ref, short_paths=False).load_metadata()
        self.assertEqual(meta.recipe.revision, commit)
def test_auto_can_be_automated():
    # https://github.com/conan-io/conan/issues/8881
    conanfile = textwrap.dedent("""
        import os
        from conans import ConanFile

        class Recipe(ConanFile):
            scm = {"type": "git",
                   "url": os.getenv("USER_EXTERNAL_URL", "auto"),
                   "revision": os.getenv("USER_EXTERNAL_COMMIT", "auto")}
    """)
    t = TestClient()
    commit = t.init_git_repo({'conanfile.py': conanfile, 'conandata.yml': ""})
    t.run_command('git remote add origin https://myrepo.com.git')
    t.run("config set general.scm_to_conandata=1")
    t.run("export . pkg/1.0@")

    def _check(client):
        # Check exported files
        ref = ConanFileReference.loads("pkg/1.0")
        package_layout = client.cache.package_layout(ref)
        exported_conanfile = load(package_layout.conanfile())
        assert exported_conanfile == conanfile
        exported_conandata = load(
            os.path.join(package_layout.export(), DATA_YML))
        conan_data = yaml.safe_load(exported_conandata)
        assert conan_data['.conan']['scm'] == {
            "type": "git",
            "url": 'https://myrepo.com.git',
            "revision": commit
        }

    _check(t)

    # Now try from another folder, doing a copy and using the env-vars
    t = TestClient(default_server_user=True)
    t.run("config set general.scm_to_conandata=1")
    t.save({"conanfile.py": conanfile})
    with environment_append({
            "USER_EXTERNAL_URL": "https://myrepo.com.git",
            "USER_EXTERNAL_COMMIT": commit
    }):
        t.run("export . pkg/1.0@")
    _check(t)

    t.run("upload * -c")
    t.run("remove * -f")
    t.run("install pkg/1.0@ --build", assert_error=True)
    assert "pkg/1.0: SCM: Getting sources from url: 'https://myrepo.com.git'" in t.out

    with environment_append({
            "USER_EXTERNAL_URL": "https://other.different.url",
            "USER_EXTERNAL_COMMIT": "invalid commit"
    }):
        t.run("install pkg/1.0@ --build", assert_error=True)
        print(t.out)
        assert "pkg/1.0: SCM: Getting sources from url: 'https://myrepo.com.git'" in t.out
Example #9
0
 def test_capture_commit_local(self):
     """
     A local repo, without remote, will have commit, but no URL
     """
     c = TestClient()
     c.save({"conanfile.py": self.conanfile})
     commit = c.init_git_repo()
     c.run("export .")
     assert "pkg/0.1: COMMIT: {}".format(commit) in c.out
     assert "pkg/0.1: URL: None" in c.out
     assert "pkg/0.1: COMMIT IN REMOTE: False" in c.out
     assert "pkg/0.1: DIRTY: False" in c.out
Example #10
0
def test_scm_with_source_layout():
    """If we have the sources in git repository"""
    conan_file = GenConanfile() \
        .with_name("app").with_version("1.0") \
        .with_settings("os", "arch", "build_type", "compiler") \
        .with_scm({"type": "git", "revision": "auto", "url": "auto"})\
        .with_cmake_build()

    conan_file = str(conan_file)
    conan_file += """
    def layout(self):
        self.folders.source = "my_src"
        self.folders.build = "build_{}".format(self.settings.build_type)
    """
    cmake = gen_cmakelists(appname="my_app", appsources=["main.cpp"])
    app = gen_function_cpp(name="main")

    remote_path, _ = create_local_git_repo({"foo": "var"}, branch="my_release")

    client = TestClient()

    client.save({
        "conanfile.py": conan_file,
        "my_src/main.cpp": app,
        "my_src/CMakeLists.txt": cmake,
        ".gitignore": "build_*\n"
    })
    client.init_git_repo()
    client.run_command('git remote add origin "%s"' %
                       remote_path.replace("\\", "/"))
    client.run_command('git push origin master')

    client.run("install . -if=install")
    client.run("build . -if=install")
    assert os.path.exists(
        os.path.join(client.current_folder, "build_Release", app_name))
    client.run("create . ")
    assert "Created package revision" in client.out
Example #11
0
    def test_capture_commit_local(self):
        """
        A local repo, without remote, will provide its own URL to the export(),
        and if it has local changes, it will be marked as dirty, and raise an error
        """
        c = TestClient()
        c.save({"conanfile.py": self.conanfile})
        commit = c.init_git_repo()
        c.run("export .")
        assert "This revision will not be buildable in other computer" in c.out
        assert "pkg/0.1: SCM COMMIT: {}".format(commit) in c.out
        assert "pkg/0.1: SCM URL: {}".format(c.current_folder.replace("\\", "/")) in c.out

        c.save({"conanfile.py": self.conanfile + "\n# something...."})
        c.run("export .", assert_error=True)
        assert "Repo is dirty, cannot capture url and commit" in c.out
Example #12
0
class SVNSCMTest(SVNLocalRepoTestCase):
    def setUp(self):
        self.ref = ConanFileReference.loads("lib/0.1@user/channel")
        self.client = TestClient()

    def test_scm_other_type_ignored(self):
        conanfile = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = ["Other stuff"]

    def build(self):
        self.output.writeln("scm: {}".format(self.scm))
'''
        self.client.save({"conanfile.py": conanfile})
        # nothing breaks
        self.client.run("create . user/channel")
        self.assertIn("['Other stuff']", self.client.out)

    def test_repeat_clone_changing_subfolder(self):
        tmp = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {{
        "type": "svn",
        "url": "{url}",
        "revision": "{revision}",
        "subfolder": "onesubfolder"
    }}
'''
        project_url, rev = self.create_project(files={"myfile": "contents"})
        conanfile = tmp.format(url=project_url, revision=rev)
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.run("create . user/channel")
        conanfile = conanfile.replace('"onesubfolder"', '"othersubfolder"')
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")
        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        self.assertIn("othersubfolder", os.listdir(folder))
        self.assertTrue(
            os.path.exists(os.path.join(folder, "othersubfolder", "myfile")))

    def test_auto_filesystem_remote_svn(self):
        # SVN origin will never be a local path (local repo has at least protocol file:///)
        pass

    def test_auto_svn(self):
        conanfile = base_svn.format(directory="None",
                                    url=_quoted("auto"),
                                    revision="auto")
        project_url, _ = self.create_project(files={
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))

        curdir = self.client.current_folder.replace("\\", "/")
        # Create the package, will copy the sources from the local folder
        self.client.run("create . user/channel")
        self.assertIn(
            "Repo origin deduced by 'auto': {}".format(project_url).lower(),
            str(self.client.out).lower())
        self.assertIn("Revision deduced by 'auto'", self.client.out)
        self.assertIn("SCM: Getting sources from folder: %s" % curdir,
                      self.client.out)
        self.assertIn("My file is copied", self.client.out)

        # Export again but now with absolute reference, so no pointer file is created nor kept
        svn = SVN(curdir)
        self.client.save({
            "conanfile.py":
            base_svn.format(url=_quoted(svn.get_remote_url()),
                            revision=svn.get_revision())
        })
        self.client.run("create . user/channel")
        self.assertNotIn("Repo origin deduced by 'auto'", self.client.out)
        self.assertNotIn("Revision deduced by 'auto'", self.client.out)
        self.assertIn(
            "SCM: Getting sources from url: '{}'".format(project_url).lower(),
            str(self.client.out).lower())
        self.assertIn("My file is copied", self.client.out)

    def test_auto_subfolder(self):
        conanfile = base_svn.replace(
            '"revision": "{revision}"', '"revision": "{revision}",\n        '
            '"subfolder": "mysub"')
        conanfile = conanfile.replace("short_paths = True",
                                      "short_paths = False")
        conanfile = conanfile.format(directory="None",
                                     url=_quoted("auto"),
                                     revision="auto")

        project_url, _ = self.create_project(files={
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))
        self.client.run("create . user/channel")

        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        self.assertTrue(
            os.path.exists(os.path.join(folder, "mysub", "myfile.txt")))
        self.assertFalse(
            os.path.exists(os.path.join(folder, "mysub", "conanfile.py")))

    def test_auto_conanfile_no_root(self):
        #  Conanfile is not in the root of the repo: https://github.com/conan-io/conan/issues/3465
        conanfile = base_svn.format(url="get_svn_remote('..')",
                                    revision="auto")
        project_url, _ = self.create_project(files={
            "conan/conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))
        self.client.run("create conan/ user/channel")

        # Check that the conanfile is on the source/conan
        ref = ConanFileReference.loads("lib/0.1@user/channel")
        source_folder = self.client.cache.package_layout(ref).source()
        self.assertTrue(
            os.path.exists(os.path.join(source_folder, "conan",
                                        "conanfile.py")))

    def test_deleted_source_folder(self):
        # SVN will always retrieve from 'remote'
        pass

    def test_excluded_repo_fies(self):
        conanfile = base_svn.format(url=_quoted("auto"), revision="auto")
        conanfile = conanfile.replace("short_paths = True",
                                      "short_paths = False")
        # SVN ignores pyc files by default:
        # http://blogs.collab.net/subversion/repository-dictated-configuration-day-3-global-ignores
        project_url, _ = self.create_project(
            files={
                "myfile": "contents",
                "ignored.pyc": "bin",
                # ".gitignore": "*.pyc\n",
                "myfile.txt": "My file!",
                "conanfile.py": conanfile
            })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))

        self.client.run("create . user/channel")
        self.assertIn("Copying sources to build folder", self.client.out)
        pref = PackageReference(
            ConanFileReference.loads("lib/0.1@user/channel"),
            NO_SETTINGS_PACKAGE_ID)
        bf = self.client.cache.package_layout(pref.ref).build(pref)
        self.assertTrue(os.path.exists(os.path.join(bf, "myfile.txt")))
        self.assertTrue(os.path.exists(os.path.join(bf, "myfile")))
        self.assertTrue(os.path.exists(os.path.join(bf, ".svn")))
        self.assertFalse(os.path.exists(os.path.join(bf, "ignored.pyc")))

    def test_local_source(self):
        curdir = self.client.current_folder.replace("\\", "/")
        conanfile = base_svn.format(url=_quoted("auto"), revision="auto")
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        project_url, _ = self.create_project(files={
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))
        self.client.save({"aditional_file.txt": "contents"})

        self.client.run("source . --source-folder=./source")
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source", "myfile.txt")))
        self.assertIn("SOURCE METHOD CALLED", self.client.out)
        # Even the not commited files are copied
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source",
                                        "aditional_file.txt")))
        self.assertIn("SCM: Getting sources from folder: %s" % curdir,
                      self.client.out)

        # Export again but now with absolute reference, so no pointer file is created nor kept
        svn = SVN(curdir)
        conanfile = base_svn.format(url=_quoted(svn.get_remote_url()),
                                    revision=svn.get_revision())
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        self.client.save({
            "conanfile.py": conanfile,
            "myfile2.txt": "My file is copied"
        })
        self.client.run_command("svn add myfile2.txt")
        self.client.run_command('svn commit -m  "commiting"')

        self.client.run("source . --source-folder=./source2")
        # myfile2 is no in the specified commit
        self.assertFalse(
            os.path.exists(os.path.join(curdir, "source2", "myfile2.txt")))
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source2", "myfile.txt")))
        self.assertIn(
            "SCM: Getting sources from url: '{}'".format(project_url).lower(),
            str(self.client.out).lower())
        self.assertIn("SOURCE METHOD CALLED", self.client.out)

    def test_local_source_subfolder(self):
        curdir = self.client.current_folder
        conanfile = base_svn.replace(
            '"revision": "{revision}"', '"revision": "{revision}",\n        '
            '"subfolder": "mysub"')
        conanfile = conanfile.format(url=_quoted("auto"), revision="auto")
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        project_url, _ = self.create_project(files={
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))

        self.client.run("source . --source-folder=./source")
        self.assertFalse(
            os.path.exists(os.path.join(curdir, "source", "myfile.txt")))
        self.assertTrue(
            os.path.exists(
                os.path.join(curdir, "source", "mysub", "myfile.txt")))
        self.assertIn("SOURCE METHOD CALLED", self.client.out)

    def test_install_checked_out(self):
        test_server = TestServer()
        self.servers = {"myremote": test_server}
        self.client = TestClient(servers=self.servers,
                                 users={"myremote": [("lasote", "mypass")]})

        conanfile = base_svn.format(url=_quoted("auto"), revision="auto")
        project_url, _ = self.create_project(files={
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))
        self.client.run("export . lasote/channel")
        self.client.run("upload lib* -c")

        # Take other client, the old client folder will be used as a remote
        client2 = TestClient(servers=self.servers,
                             users={"myremote": [("lasote", "mypass")]})
        client2.run("install lib/0.1@lasote/channel --build")
        self.assertIn("My file is copied", client2.out)

    def test_source_removed_in_local_cache(self):
        conanfile = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    scm = {
        "type": "svn",
        "url": "auto",
        "revision": "auto",
    }

    def build(self):
        contents = tools.load("myfile")
        self.output.warn("Contents: %s" % contents)

'''
        project_url, _ = self.create_project(files={
            "myfile": "contents",
            "conanfile.py": conanfile
        })
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))

        self.client.run("create . lib/1.0@user/channel")
        self.assertIn("Contents: contents", self.client.out)
        self.client.save({"myfile": "Contents 2"})
        self.client.run("create . lib/1.0@user/channel")
        self.assertIn("Contents: Contents 2", self.client.out)

    def test_submodule(self):
        # SVN has no submodules, may add something related to svn:external?
        pass

    def test_source_method_export_sources_and_scm_mixed(self):
        project_url, rev = self.create_project(files={"myfile": "contents"})
        project_url = project_url.replace(" ", "%20")
        self.client.run_command('svn co "{url}" "{path}"'.format(
            url=project_url, path=self.client.current_folder))

        conanfile = '''
import os
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    exports_sources = "file.txt"
    scm = {{
        "type": "svn",
        "url": "{url}",
        "revision": "{rev}",
        "subfolder": "src"
    }}

    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
        assert(os.path.exists("file.txt"))
        assert(os.path.exists(os.path.join("src", "myfile")))
        tools.save("cosa.txt", "contents")

    def build(self):
        assert(os.path.exists("file.txt"))
        assert(os.path.exists("cosa.txt"))
        self.output.warn("BUILD METHOD CALLED")
'''.format(url=project_url, rev=rev)
        self.client.save({
            "conanfile.py": conanfile,
            "file.txt": "My file is copied"
        })
        self.client.run("create . user/channel")
        self.assertIn("SOURCE METHOD CALLED", self.client.out)
        self.assertIn("BUILD METHOD CALLED", self.client.out)

    def test_non_commited_changes_export(self):
        conanfile = base_git.format(revision="auto", url='"auto"')
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run_command('git remote add origin https://myrepo.com.git')
        # Dirty file
        self.client.save({"dirty": "you dirty contents"})

        for command in ("export .", "create ."):
            self.client.run(command)
            self.assertIn(
                "WARN: There are uncommitted changes, skipping the replacement "
                "of 'scm.url' and 'scm.revision' auto fields. "
                "Use --ignore-dirty to force it.", self.client.out)

            # We confirm that the replacement hasn't been done
            ref = ConanFileReference.loads("lib/0.1@")
            folder = self.client.cache.package_layout(ref).export()
            conanfile_contents = load(os.path.join(folder, "conanfile.py"))
            self.assertIn('"revision": "auto"', conanfile_contents)
            self.assertIn('"url": "auto"', conanfile_contents)

        # We repeat the export/create but now using the --ignore-dirty
        for command in ("export .", "create ."):
            self.client.run("{} --ignore-dirty".format(command))
            self.assertNotIn(
                "WARN: There are uncommitted changes, skipping the replacement "
                "of 'scm.url' and 'scm.revision' auto fields. "
                "Use --ignore-dirty to force it.", self.client.out)
            # We confirm that the replacement has been done
            ref = ConanFileReference.loads("lib/0.1@")
            folder = self.client.cache.package_layout(ref).export()
            conanfile_contents = load(os.path.join(folder, "conanfile.py"))
            self.assertNotIn('"revision": "auto"', conanfile_contents)
            self.assertNotIn('"url": "auto"', conanfile_contents)

    def test_double_create(self):
        # https://github.com/conan-io/conan/issues/5195#issuecomment-551848955
        self.client = TestClient(default_server_user=True)
        conanfile = str(GenConanfile().with_scm({
            "type": "git",
            "revision": "auto",
            "url": "auto"
        }).with_import("import os").with_import(
            "from conans import tools").with_name("lib").with_version("1.0"))
        conanfile += """
    def build(self):
        contents = tools.load("bla.sh")
        self.output.warn("Bla? {}".format(contents))
        """
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run_command('git remote add origin https://myrepo.com.git')
        #  modified blah.sh
        self.client.save({"bla.sh": "bla bla"})
        self.client.run("create . user/channel")
        self.assertIn("Bla? bla bla", self.client.out)
        #  modified blah.sh again
        self.client.save({"bla.sh": "bla2 bla2"})
        # Run conan create again
        self.client.run("create . user/channel")
        self.assertIn("Bla? bla2 bla2", self.client.out)
Example #13
0
class GitSCMTest(unittest.TestCase):
    def setUp(self):
        self.ref = ConanFileReference.loads("lib/0.1@user/channel")
        self.client = TestClient()

    def _commit_contents(self):
        self.client.run_command("git init .")
        self.client.run_command('git config user.email "*****@*****.**"')
        self.client.run_command('git config user.name "Your Name"')
        self.client.run_command("git add .")
        self.client.run_command('git commit -m  "commiting"')

    def test_scm_other_type_ignored(self):
        conanfile = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = ["Other stuff"]

    def build(self):
        self.output.writeln("scm: {}".format(self.scm))
'''
        self.client.save({"conanfile.py": conanfile})
        # nothing breaks
        self.client.run("create . user/channel")
        self.assertIn("['Other stuff']", self.client.out)

    def test_repeat_clone_changing_subfolder(self):
        tmp = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {{
        "type": "git",
        "url": "{url}",
        "revision": "{revision}",
        "subfolder": "onesubfolder"
    }}
'''
        path, commit = create_local_git_repo({"myfile": "contents"},
                                             branch="my_release")
        conanfile = tmp.format(url=path, revision=commit)
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.run("create . user/channel")
        conanfile = conanfile.replace('"onesubfolder"', '"othersubfolder"')
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")
        folder = self.client.cache.package_layout(self.ref).source()
        self.assertIn("othersubfolder", os.listdir(folder))
        self.assertTrue(
            os.path.exists(os.path.join(folder, "othersubfolder", "myfile")))

    def test_auto_filesystem_remote_git(self):
        # https://github.com/conan-io/conan/issues/3109
        conanfile = base_git.format(directory="None",
                                    url=_quoted("auto"),
                                    revision="auto")
        repo = temp_folder()
        self.client.save(
            {
                "conanfile.py": conanfile,
                "myfile.txt": "My file is copied"
            }, repo)
        with self.client.chdir(repo):
            self.client.run_command("git init .")
            self.client.run_command('git config user.email "*****@*****.**"')
            self.client.run_command('git config user.name "Your Name"')
            self.client.run_command("git add .")
            self.client.run_command('git commit -m  "commiting"')
        self.client.run_command('git clone "%s" .' % repo)
        self.client.run("export . user/channel")
        self.assertIn("WARN: Repo origin looks like a local path",
                      self.client.out)
        self.client.run("remove lib/0.1* -s -f"
                        )  # Remove the source folder, it will get from url
        self.client.run("install lib/0.1@user/channel --build")
        self.assertIn("lib/0.1@user/channel: SCM: Getting sources from url:",
                      self.client.out)

    def test_auto_git(self):
        curdir = get_cased_path(self.client.current_folder).replace("\\", "/")
        conanfile = base_git.format(directory="None",
                                    url=_quoted("auto"),
                                    revision="auto")
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run("export . user/channel")
        self.assertIn(
            "WARN: Repo origin cannot be deduced, 'auto' fields won't be replaced",
            self.client.out)

        self.client.run_command('git remote add origin https://myrepo.com.git')

        # Create the package, will copy the sources from the local folder
        self.client.run("create . user/channel")
        self.assertIn("Repo origin deduced by 'auto': https://myrepo.com.git",
                      self.client.out)
        self.assertIn("Revision deduced by 'auto'", self.client.out)
        self.assertIn("SCM: Getting sources from folder: %s" % curdir,
                      self.client.out)
        self.assertIn("My file is copied", self.client.out)

        # check blank lines are respected in replacement
        self.client.run("get lib/0.1@user/channel")
        self.assertIn("""}

    def build(self):""", self.client.out)

        # Export again but now with absolute reference, so no sources are copied from the local dir
        git = Git(curdir)
        self.client.save({
            "conanfile.py":
            base_git.format(url=_quoted(curdir), revision=git.get_revision())
        })
        self.client.run("create . user/channel")
        self.assertNotIn("Repo origin deduced by 'auto'", self.client.out)
        self.assertNotIn("Revision deduced by 'auto'", self.client.out)
        self.assertNotIn("Getting sources from folder: %s" % curdir,
                         self.client.out)
        self.assertIn("SCM: Getting sources from url: '%s'" % curdir,
                      self.client.out)
        self.assertIn("My file is copied", self.client.out)

    def test_auto_subfolder(self):
        conanfile = base_git.replace(
            '"revision": "{revision}"', '"revision": "{revision}",\n        '
            '"subfolder": "mysub"')
        conanfile = conanfile.replace("short_paths = True",
                                      "short_paths = False")
        conanfile = conanfile.format(directory="None",
                                     url=_quoted("auto"),
                                     revision="auto")
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run_command('git remote add origin https://myrepo.com.git')
        self.client.run("create . user/channel")

        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        self.assertTrue(
            os.path.exists(os.path.join(folder, "mysub", "myfile.txt")))
        self.assertFalse(
            os.path.exists(os.path.join(folder, "mysub", "conanfile.py")))

    def test_ignore_dirty_subfolder(self):
        # https://github.com/conan-io/conan/issues/6070
        conanfile = textwrap.dedent("""
            import os
            from conans import ConanFile, tools

            class ConanLib(ConanFile):
                name = "lib"
                version = "0.1"
                short_paths = True
                scm = {
                    "type": "git",
                    "url": "auto",
                    "revision": "auto",
                }

                def build(self):
                    path = os.path.join("base_file.txt")
                    assert os.path.exists(path)
        """)
        self.client.save({
            "test/main/conanfile.py": conanfile,
            "base_file.txt": "foo"
        })
        self.client.init_git_repo()
        self.client.run_command('git remote add origin https://myrepo.com.git')

        # Introduce changes
        self.client.save({"dirty_file.txt": "foo"})
        # The build() method will verify that the files from the repository are copied ok
        self.client.run("create test/main/conanfile.py user/channel")
        self.assertIn("Package '{}' created".format(NO_SETTINGS_PACKAGE_ID),
                      self.client.out)

    def test_auto_conanfile_no_root(self):
        """
        Conanfile is not in the root of the repo: https://github.com/conan-io/conan/issues/3465
        """
        conanfile = base_git.format(url=_quoted("auto"), revision="auto")
        self.client.save({
            "conan/conanfile.py": conanfile,
            "myfile.txt": "content of my file"
        })
        self._commit_contents()
        self.client.run_command('git remote add origin https://myrepo.com.git')

        # Create the package
        self.client.run("create conan/ user/channel")

        # Check that the conanfile is on the source/conan
        ref = ConanFileReference.loads("lib/0.1@user/channel")
        source_folder = self.client.cache.package_layout(ref).source()
        self.assertTrue(
            os.path.exists(os.path.join(source_folder, "conan",
                                        "conanfile.py")))

    def test_deleted_source_folder(self):
        path, _ = create_local_git_repo({"myfile": "contents"},
                                        branch="my_release")
        conanfile = base_git.format(url=_quoted("auto"), revision="auto")
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run_command('git remote add origin "%s"' %
                                path.replace("\\", "/"))
        self.client.run_command('git push origin master')
        self.client.run("export . user/channel")

        # delete old source, but it doesn't matter because the sources are in the cache
        rmdir(self.client.current_folder)
        new_curdir = temp_folder()
        self.client.current_folder = new_curdir

        self.client.run("install lib/0.1@user/channel --build")
        self.assertNotIn(
            "Getting sources from url: '%s'" % path.replace("\\", "/"),
            self.client.out)

        # If the remove the source folder, then it is fetched from the "remote" doing an install
        self.client.run("remove lib/0.1@user/channel -f -s")
        self.client.run("install lib/0.1@user/channel --build")
        self.assertIn(
            "SCM: Getting sources from url: '%s'" % path.replace("\\", "/"),
            self.client.out)

    def test_excluded_repo_files(self):
        conanfile = base_git.format(url=_quoted("auto"), revision="auto")
        conanfile = conanfile.replace("short_paths = True",
                                      "short_paths = False")
        gitignore = textwrap.dedent("""
            *.pyc
            my_excluded_folder
            other_folder/excluded_subfolder
            """)
        self.client.init_git_repo(
            {
                "myfile": "contents",
                "ignored.pyc": "bin",
                ".gitignore": gitignore,
                "myfile.txt": "My file!",
                "my_excluded_folder/some_file": "hey Apple!",
                "other_folder/excluded_subfolder/some_file": "hey Apple!",
                "other_folder/valid_file": "!",
                "conanfile.py": conanfile
            },
            branch="my_release")

        self.client.run("create . user/channel")
        self.assertIn("Copying sources to build folder", self.client.out)
        pref = PackageReference(
            ConanFileReference.loads("lib/0.1@user/channel"),
            NO_SETTINGS_PACKAGE_ID)
        bf = self.client.cache.package_layout(pref.ref).build(pref)
        self.assertTrue(os.path.exists(os.path.join(bf, "myfile.txt")))
        self.assertTrue(os.path.exists(os.path.join(bf, "myfile")))
        self.assertTrue(os.path.exists(os.path.join(bf, ".git")))
        self.assertFalse(os.path.exists(os.path.join(bf, "ignored.pyc")))
        self.assertFalse(os.path.exists(os.path.join(bf,
                                                     "my_excluded_folder")))
        self.assertTrue(
            os.path.exists(os.path.join(bf, "other_folder", "valid_file")))
        self.assertFalse(
            os.path.exists(
                os.path.join(bf, "other_folder", "excluded_subfolder")))

    def test_local_source(self):
        curdir = self.client.current_folder.replace("\\", "/")
        conanfile = base_git.format(url=_quoted("auto"), revision="auto")
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.save({"aditional_file.txt": "contents"})

        self.client.run("source . --source-folder=./source")
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source", "myfile.txt")))
        self.assertIn("SOURCE METHOD CALLED", self.client.out)
        # Even the not commited files are copied
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source",
                                        "aditional_file.txt")))
        self.assertIn("SCM: Getting sources from folder: %s" % curdir,
                      str(self.client.out).replace("\\", "/"))

        # Export again but now with absolute reference, so no pointer file is created nor kept
        git = Git(curdir.replace("\\", "/"))
        conanfile = base_git.format(url=_quoted(curdir.replace("\\", "/")),
                                    revision=git.get_revision())
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        self.client.save({
            "conanfile.py": conanfile,
            "myfile2.txt": "My file is copied"
        })
        self.client.init_git_repo()
        self.client.run("source . --source-folder=./source2")
        # myfile2 is no in the specified commit
        self.assertFalse(
            os.path.exists(os.path.join(curdir, "source2", "myfile2.txt")))
        self.assertTrue(
            os.path.exists(os.path.join(curdir, "source2", "myfile.txt")))
        self.assertIn(
            "SCM: Getting sources from url: '%s'" % curdir.replace("\\", "/"),
            self.client.out)
        self.assertIn("SOURCE METHOD CALLED", self.client.out)

    def test_local_source_subfolder(self):
        curdir = self.client.current_folder
        conanfile = base_git.replace(
            '"revision": "{revision}"', '"revision": "{revision}",\n        '
            '"subfolder": "mysub"')
        conanfile = conanfile.format(url=_quoted("auto"), revision="auto")
        conanfile += """
    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
"""
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()

        self.client.run("source . --source-folder=./source")
        self.assertFalse(
            os.path.exists(os.path.join(curdir, "source", "myfile.txt")))
        self.assertTrue(
            os.path.exists(
                os.path.join(curdir, "source", "mysub", "myfile.txt")))
        self.assertIn("SOURCE METHOD CALLED", self.client.out)

    @parameterized.expand([
        ("local", "v1.0", True), ("local", None, False),
        ("https://github.com/conan-io/conan.git", "0.22.1", True),
        ("https://github.com/conan-io/conan.git",
         "c6cc15fa2f4b576bd70c9df11942e61e5cc7d746", False)
    ])
    def test_shallow_clone_remote(self, remote, revision, is_tag):
        # https://github.com/conan-io/conan/issues/5570
        self.client = TestClient()

        # "remote" git
        if remote == "local":
            remote, rev = create_local_git_repo(
                tags=[revision] if is_tag else None,
                files={"conans/model/username.py": "foo"})
            if revision is None:  # Get the generated commit
                revision = rev

        # Use explicit URL to avoid local optimization (scm_folder.txt)
        conanfile = '''
import os
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {"type": "git", "url": "%s", "revision": "%s"}

    def build(self):
        assert os.path.exists(os.path.join(self.build_folder, "conans", "model", "username.py"))
''' % (remote, revision)
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")

    def test_install_checked_out(self):
        test_server = TestServer()
        self.servers = {"myremote": test_server}
        self.client = TestClient(servers=self.servers,
                                 users={"myremote": [("lasote", "mypass")]})

        curdir = self.client.current_folder.replace("\\", "/")
        conanfile = base_git.format(url=_quoted("auto"), revision="auto")
        self.client.save({
            "conanfile.py": conanfile,
            "myfile.txt": "My file is copied"
        })
        self.client.init_git_repo()
        cmd = 'git remote add origin "%s"' % curdir
        self.client.run_command(cmd)
        self.client.run("export . lasote/channel")
        self.client.run("upload lib* -c")

        # Take other client, the old client folder will be used as a remote
        client2 = TestClient(servers=self.servers,
                             users={"myremote": [("lasote", "mypass")]})
        client2.run("install lib/0.1@lasote/channel --build")
        self.assertIn("My file is copied", client2.out)

    def test_source_removed_in_local_cache(self):
        conanfile = textwrap.dedent('''
            from conans import ConanFile, tools

            class ConanLib(ConanFile):
                scm = {
                    "type": "git",
                    "url": "auto",
                    "revision": "auto",
                }

                def build(self):
                    contents = tools.load("myfile")
                    self.output.warn("Contents: %s" % contents)
            ''')

        self.client.init_git_repo(
            {
                "myfile": "contents",
                "conanfile.py": conanfile
            },
            branch="my_release",
            origin_url="https://myrepo.com.git")
        self.client.run("create . lib/1.0@user/channel")
        self.assertIn("Contents: contents", self.client.out)
        self.client.save({"myfile": "Contents 2"})
        self.client.run("create . lib/1.0@user/channel")
        self.assertIn("Contents: Contents 2", self.client.out)

    def test_submodule(self):
        subsubmodule, _ = create_local_git_repo({"subsubmodule": "contents"})
        submodule, _ = create_local_git_repo({"submodule": "contents"},
                                             submodules=[subsubmodule])
        path, commit = create_local_git_repo({"myfile": "contents"},
                                             branch="my_release",
                                             submodules=[submodule])

        def _relative_paths(folder):
            submodule_path = os.path.join(
                folder, os.path.basename(os.path.normpath(submodule)))
            subsubmodule_path = os.path.join(
                submodule_path,
                os.path.basename(os.path.normpath(subsubmodule)))
            return submodule_path, subsubmodule_path

        # Check old (default) behaviour
        tmp = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {{
        "type": "git",
        "url": "{url}",
        "revision": "{revision}"
    }}
'''
        conanfile = tmp.format(url=path, revision=commit)
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")

        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        submodule_path, _ = _relative_paths(folder)
        self.assertTrue(os.path.exists(os.path.join(folder, "myfile")))
        self.assertFalse(
            os.path.exists(os.path.join(submodule_path, "submodule")))

        # Check invalid value
        tmp = '''
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {{
        "type": "git",
        "url": "{url}",
        "revision": "{revision}",
        "submodule": "{submodule}"
    }}
'''
        conanfile = tmp.format(url=path, revision=commit, submodule="invalid")
        self.client.save({"conanfile.py": conanfile})

        self.client.run("create . user/channel", assert_error=True)
        self.assertIn("Invalid 'submodule' attribute value in the 'scm'.",
                      self.client.out)

        # Check shallow
        conanfile = tmp.format(url=path, revision=commit, submodule="shallow")
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")

        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        submodule_path, subsubmodule_path = _relative_paths(folder)
        self.assertTrue(os.path.exists(os.path.join(folder, "myfile")))
        self.assertTrue(
            os.path.exists(os.path.join(submodule_path, "submodule")))
        self.assertFalse(
            os.path.exists(os.path.join(subsubmodule_path, "subsubmodule")))

        # Check recursive
        conanfile = tmp.format(url=path,
                               revision=commit,
                               submodule="recursive")
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")

        ref = ConanFileReference.loads("lib/0.1@user/channel")
        folder = self.client.cache.package_layout(ref).source()
        submodule_path, subsubmodule_path = _relative_paths(folder)
        self.assertTrue(os.path.exists(os.path.join(folder, "myfile")))
        self.assertTrue(
            os.path.exists(os.path.join(submodule_path, "submodule")))
        self.assertTrue(
            os.path.exists(os.path.join(subsubmodule_path, "subsubmodule")))

    def test_scm_bad_filename(self):
        # Fixes: #3500
        badfilename = "\xE3\x81\x82badfile.txt"
        path, _ = create_local_git_repo({"goodfile.txt": "good contents"},
                                        branch="my_release")
        save(
            to_file_bytes(os.path.join(self.client.current_folder,
                                       badfilename)), "contents")
        self.client.run_command('git remote add origin "%s"' %
                                path.replace("\\", "/"),
                                cwd=path)

        conanfile = '''
import os
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    scm = {
        "type": "git",
        "url": "auto",
        "revision": "auto"
    }

    def build(self):
        pass
'''
        self.client.current_folder = path
        self.client.save({"conanfile.py": conanfile})
        self.client.run("create . user/channel")

    def test_source_method_export_sources_and_scm_mixed(self):
        path, _ = create_local_git_repo({"myfile": "contents"},
                                        branch="my_release")

        conanfile = '''
import os
from conans import ConanFile, tools

class ConanLib(ConanFile):
    name = "lib"
    version = "0.1"
    exports_sources = "file.txt"
    scm = {
        "type": "git",
        "url": "%s",
        "revision": "my_release",
        "subfolder": "src/nested"
    }

    def source(self):
        self.output.warn("SOURCE METHOD CALLED")
        assert(os.path.exists("file.txt"))
        assert(os.path.exists(os.path.join("src", "nested", "myfile")))
        tools.save("cosa.txt", "contents")

    def build(self):
        assert(os.path.exists("file.txt"))
        assert(os.path.exists("cosa.txt"))
        self.output.warn("BUILD METHOD CALLED")
''' % path
        self.client.save({
            "conanfile.py": conanfile,
            "file.txt": "My file is copied"
        })
        self.client.run("create . user/channel")
        self.assertIn("SOURCE METHOD CALLED", self.client.out)
        self.assertIn("BUILD METHOD CALLED", self.client.out)

    def test_scm_serialization(self):
        data = {
            "url": "myurl",
            "revision": "myrevision",
            "username": "******",
            "password": "******",
            "type": "git",
            "verify_ssl": True,
            "subfolder": "mysubfolder"
        }
        conanfile = namedtuple("ConanfileMock", "scm")(data)
        scm_data = SCMData(conanfile)

        expected_output = '{"password": "******", "revision": "myrevision",' \
                          ' "subfolder": "mysubfolder", "type": "git", "url": "myurl",' \
                          ' "username": "******"}'
        self.assertEqual(str(scm_data), expected_output)

    def test_git_delegated_function(self):
        conanfile = textwrap.dedent("""
            import os
            from conans import ConanFile
            from conans.client.tools.scm import Git

            def get_revision():
                here = os.path.dirname(__file__)
                git = Git(here)
                return git.get_commit()

            def get_url():
                def nested_url():
                    here = os.path.dirname(__file__)
                    git = Git(here)
                    return git.get_remote_url()
                return nested_url()

            class MyLib(ConanFile):
                name = "issue"
                version = "3831"
                scm = {'type': 'git', 'url': get_url(), 'revision': get_revision()}
            """)
        commit = self.client.init_git_repo({"conanfile.py": conanfile})

        self.client.run("export . user/channel")
        ref = ConanFileReference.loads("issue/3831@user/channel")
        exported_conanfile = self.client.cache.package_layout(ref).conanfile()
        content = load(exported_conanfile)
        self.assertIn(commit, content)

    def test_delegated_python_code(self):
        client = TestClient()
        code_file = textwrap.dedent("""
            from conans.tools import Git
            from conans import ConanFile

            def get_commit(repo_path):
                git = Git(repo_path)
                return git.get_commit()

            class MyLib(ConanFile):
                pass
            """)
        client.save({"conanfile.py": code_file})
        client.run("export . tool/0.1@user/testing")

        conanfile = textwrap.dedent("""
            import os
            from conans import ConanFile, python_requires
            from conans.tools import load
            tool = python_requires("tool/0.1@user/testing")

            class MyLib(ConanFile):
                scm = {'type': 'git', 'url': '%s',
                       'revision': tool.get_commit(os.path.dirname(__file__))}
                def build(self):
                    self.output.info("File: {}".format(load("file.txt")))
            """ % client.current_folder.replace("\\", "/"))

        commit = client.init_git_repo({
            "conanfile.py": conanfile,
            "file.txt": "hello!"
        })
        client.run("export . pkg/0.1@user/channel")
        ref = ConanFileReference.loads("pkg/0.1@user/channel")
        exported_conanfile = client.cache.package_layout(ref).conanfile()
        content = load(exported_conanfile)
        self.assertIn(commit, content)
Example #14
0
def test_third_party_patch_flow():
    """ this test emulates the work of a developer contributing recipes to ConanCenter, and having
    to do multiple patches to the original library source code:
    - Everything is local, not messing with the cache
    - Using layout() to define location of things
    """
    conanfile = textwrap.dedent(r"""
        import os
        from conan import ConanFile
        from conan.tools.files import save, load, apply_conandata_patches

        class Pkg(ConanFile):
            name = "mypkg"
            version = "1.0"
            exports_sources = "*"

            def layout(self):
                self.folders.source = "src"
                self.folders.build = "build"

            def source(self):
                # emulate a download from web site
                save(self, "myfile.cpp", "mistake1\nsomething\nmistake2\nmistake3\nsome\n")
                apply_conandata_patches(self)

            def build(self):
                content = load(self,  os.path.join(self.source_folder, "myfile.cpp"))
                for i in (1, 2, 3):
                    if "mistake{}".format(i) in content:
                        raise Exception("MISTAKE{} BUILD!".format(i))
        """)

    client = TestClient()
    client.save({"conanfile.py": conanfile, "conandata.yml": ""})
    client.run("install .")
    client.run("source .")
    client.run("build .", assert_error=True)
    assert "MISTAKE1 BUILD!" in client.out

    # user decides to create patches, first init the repo
    client.init_git_repo(folder="src")  # Using helper for user/email repo init
    client.save(
        {"src/myfile.cpp": "correct1\nsomething\nmistake2\nmistake3\nsome\n"})
    # compute the patch
    mkdir(os.path.join(client.current_folder, "patches"))
    client.run_command("cd src && git diff > ../patches/patch1")
    client.run_command("cd src && git add . && git commit -m patch1")
    conandata = textwrap.dedent("""
        patches:
          "1.0":
            - patch_file: "patches/patch1"
        """)
    client.save({"conandata.yml": conandata})

    client.run("source .")
    client.run("build .", assert_error=True)
    assert "MISTAKE2 BUILD!" in client.out

    client.save(
        {"src/myfile.cpp": "correct1\nsomething\ncorrect2\nmistake3\nsome\n"})
    # compute the patch
    mkdir(os.path.join(client.current_folder, "patches"))
    client.run_command("cd src && git diff > ../patches/patch2")
    client.run_command("cd src && git add . && git commit -m patch1")

    conandata = textwrap.dedent("""
        patches:
          "1.0":
            - patch_file: "patches/patch1"
            - patch_file: "patches/patch2"
        """)
    client.save({"conandata.yml": conandata})
    client.run("source .")
    client.run("build .", assert_error=True)
    assert "MISTAKE3 BUILD!" in client.out

    client.save(
        {"src/myfile.cpp": "correct1\nsomething\ncorrect2\ncorrect3\nsome\n"})
    # compute the patch
    mkdir(os.path.join(client.current_folder, "patches"))
    client.run_command("cd src && git diff > ../patches/patch3")
    client.run_command("cd src && git add . && git commit -m patch1")

    conandata = textwrap.dedent("""
           patches:
             "1.0":
               - patch_file: "patches/patch1"
               - patch_file: "patches/patch2"
               - patch_file: "patches/patch3"
           """)
    client.save({"conandata.yml": conandata})
    client.run("source .")
    client.run("build .")
    assert "conanfile.py (mypkg/1.0): Calling build()" in client.out

    # of course create should work too
    client.run("create .")
    assert "mypkg/1.0: Created package" in client.out