Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add --output option to conan new command #17359

Merged
merged 2 commits into from
Nov 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion conan/api/subapi/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When no name was passed, an uppercase one was being used!

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):
Expand Down
8 changes: 5 additions & 3 deletions conan/cli/commands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -59,18 +61,18 @@ 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)
output.success("File saved: %s" % f)

# 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)
Expand Down
34 changes: 22 additions & 12 deletions test/integration/command/new_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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")

Expand All @@ -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")
Expand All @@ -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}}"
Expand All @@ -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}}"
Expand All @@ -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}}"
Expand All @@ -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)
Expand All @@ -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")
Expand All @@ -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"))