diff --git a/conan/api/subapi/new.py b/conan/api/subapi/new.py index b9732daea35..8b3089a0c19 100644 --- a/conan/api/subapi/new.py +++ b/conan/api/subapi/new.py @@ -93,9 +93,11 @@ def _read_files(self, template_folder): @staticmethod def render(template_files, definitions): result = {} - name = definitions.get("name", "Pkg") + name = definitions.get("name", "pkg") if isinstance(name, list): raise ConanException(f"name argument can't be multiple: {name}") + if name != name.lower(): + raise ConanException(f"name argument must be lowercase: {name}") definitions["conan_version"] = __version__ def ensure_list(key): diff --git a/conan/cli/commands/new.py b/conan/cli/commands/new.py index 18b3b0c9612..ecc9615893a 100644 --- a/conan/cli/commands/new.py +++ b/conan/cli/commands/new.py @@ -24,6 +24,8 @@ def new(conan_api, parser, *args): parser.add_argument("-d", "--define", action="append", help="Define a template argument as key=value, e.g., -d name=mypkg") parser.add_argument("-f", "--force", action='store_true', help="Overwrite file if it already exists") + parser.add_argument("-o", "--output", help="Output folder for the generated files", + default=os.getcwd()) args = parser.parse_args(*args) # Manually parsing the remainder @@ -59,10 +61,10 @@ def new(conan_api, parser, *args): # Saving the resulting files output = ConanOutput() - cwd = os.getcwd() + output_folder = args.output # Making sure they don't overwrite existing files for f, v in sorted(template_files.items()): - path = os.path.join(cwd, f) + path = os.path.join(output_folder, f) if os.path.exists(path) and not args.force: raise ConanException(f"File '{f}' already exists, and --force not defined, aborting") save(path, v) @@ -70,7 +72,7 @@ def new(conan_api, parser, *args): # copy non-templates for f, v in sorted(non_template_files.items()): - path = os.path.join(cwd, f) + path = os.path.join(output_folder, f) if os.path.exists(path) and not args.force: raise ConanException(f"File '{f}' already exists, and --force not defined, aborting") shutil.copy2(v, path) diff --git a/test/integration/command/new_test.py b/test/integration/command/new_test.py index 0dbb71deac3..55d5103b828 100644 --- a/test/integration/command/new_test.py +++ b/test/integration/command/new_test.py @@ -11,7 +11,7 @@ class TestNewCommand: def test_new_cmake_lib(self): - client = TestClient() + client = TestClient(light=True) client.run("new cmake_lib -d name=pkg -d version=1.3") conanfile = client.load("conanfile.py") assert "CMakeToolchain" in conanfile @@ -25,7 +25,7 @@ def test_new_cmake_lib(self): assert "pkg/1.3@myuser/testing" in client.out def test_new_cmake_exe(self): - client = TestClient() + client = TestClient(light=True) client.run("new cmake_exe -d name=pkg -d version=1.3") conanfile = client.load("conanfile.py") assert "CMakeToolchain" in conanfile @@ -37,7 +37,7 @@ def test_new_cmake_exe(self): assert "pkg/1.3@myuser/testing" in client.out def test_new_basic_template(self): - tc = TestClient() + tc = TestClient(light=True) tc.run("new basic") assert '# self.requires("zlib/1.2.13")' in tc.load("conanfile.py") @@ -48,7 +48,7 @@ def test_new_basic_template(self): assert 'name = "mygame"' in conanfile def test_new_defaults(self): - c = TestClient() + c = TestClient(light=True) for t in ("cmake_lib", "cmake_exe", "meson_lib", "meson_exe", "msbuild_lib", "msbuild_exe", "bazel_lib", "bazel_exe", "autotools_lib", "autotools_exe"): c.run(f"new {t} -f") @@ -66,7 +66,7 @@ class TestNewCommandUserTemplate: @pytest.mark.parametrize("folder", ("mytemplate", "sub/mytemplate")) def test_user_template(self, folder): - client = TestClient() + client = TestClient(light=True) template1 = textwrap.dedent(""" class Conan(ConanFile): name = "{{name}}" @@ -83,7 +83,7 @@ class Conan(ConanFile): def test_user_template_abs(self): tmp_folder = temp_folder() - client = TestClient() + client = TestClient(light=True) template1 = textwrap.dedent(""" class Conan(ConanFile): name = "{{name}}" @@ -94,13 +94,13 @@ class Conan(ConanFile): assert 'name = "hello"' in conanfile def test_user_template_filenames(self): - client = TestClient() + client = TestClient(light=True) save(os.path.join(client.cache_folder, "templates/command/new/mytemplate/{{name}}"), "Hi!") client.run(f"new mytemplate -d name=pkg.txt") assert "Hi!" == client.load("pkg.txt") def test_skip_files(self): - client = TestClient() + client = TestClient(light=True) template1 = textwrap.dedent(""" class Conan(ConanFile): name = "{{name}}" @@ -121,7 +121,7 @@ class Conan(ConanFile): def test_template_image_files(self): """ problematic files that we dont want to render with Jinja, like PNG or other binaries, have to be explicitly excluded from render""" - client = TestClient() + client = TestClient(light=True) template_dir = "templates/command/new/t_dir" png = "$&(){}{}{{}{}" save(os.path.join(client.cache_folder, template_dir, "myimage.png"), png) @@ -137,12 +137,12 @@ def test_template_image_files(self): class TestNewErrors: def test_template_errors(self): - client = TestClient() + client = TestClient(light=True) client.run("new mytemplate", assert_error=True) assert "ERROR: Template doesn't exist" in client.out def test_forced(self): - client = TestClient() + client = TestClient(light=True) client.run("new cmake_lib -d name=hello -d version=0.1") client.run("new cmake_lib -d name=hello -d version=0.1", assert_error=True) client.run("new cmake_lib -d name=bye -d version=0.2 --force") @@ -151,10 +151,20 @@ def test_forced(self): assert 'version = "0.2"' in conanfile def test_duplicated(self): - client = TestClient() + client = TestClient(light=True) client.run("new cmake_lib -d name=hello -d name=0.1", assert_error=True) assert "ERROR: name argument can't be multiple: ['hello', '0.1']" in client.out # It will create a list and assign to it, but it will not fail ugly client.run("new cmake_lib -d name=pkg -d version=0.1 -d version=0.2", assert_error=True) assert "ERROR: version argument can't be multiple: ['0.1', '0.2']" in client.out + + def test_name_uppercase(self): + client = TestClient(light=True) + client.run("new cmake_lib -d name=Hello", assert_error=True) + assert "ERROR: name argument must be lowercase: Hello" in client.out + + def test_new_change_folder(self): + client = TestClient(light=True) + client.run("new cmake_lib -d name=hello -d version=0.1 -o=myfolder") + assert os.path.exists(os.path.join(client.current_folder, "myfolder", "conanfile.py"))