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 barebones template to conan new #12802

Merged
merged 13 commits into from
Jan 2, 2023
6 changes: 5 additions & 1 deletion conan/api/subapi/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self, conan_api):

@api_method
def get_builtin_template(self, template_name):
from conan.internal.api.new.basic import basic_file
from conan.internal.api.new.alias_new import alias_file
from conan.internal.api.new.cmake_exe import cmake_exe_files
from conan.internal.api.new.cmake_lib import cmake_lib_files
Expand All @@ -28,7 +29,8 @@ def get_builtin_template(self, template_name):
from conan.internal.api.new.bazel_exe import bazel_exe_files
from conan.internal.api.new.autotools_lib import autotools_lib_files
from conan.internal.api.new.autoools_exe import autotools_exe_files
new_templates = {"cmake_lib": cmake_lib_files,
new_templates = {"basic": basic_file,
"cmake_lib": cmake_lib_files,
"cmake_exe": cmake_exe_files,
"meson_lib": meson_lib_files,
"meson_exe": meson_exe_files,
Expand Down Expand Up @@ -82,12 +84,14 @@ def _read_files(self, template_folder):

return template_files, non_template_files


@staticmethod
def render(template_files, definitions):
result = {}
name = definitions.get("name", "Pkg")
definitions["conan_version"] = __version__
definitions["package_name"] = name.replace("-", "_").replace("+", "_").replace(".", "_")
definitions["as_iterable"] = lambda x: [x] if isinstance(x, str) else x
for k, v in template_files.items():
k = Template(k, keep_trailing_newline=True, undefined=StrictUndefined).render(**definitions)
v = Template(v, keep_trailing_newline=True, undefined=StrictUndefined).render(**definitions)
Expand Down
21 changes: 15 additions & 6 deletions conan/cli/commands/new.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@
@conan_command(group="Creator")
def new(conan_api, parser, *args):
"""
Create a new recipe (with conanfile.py and other files) from a predefined template
Create a new recipe (with conanfile.py and other files) from either a predefined or a user-defined template
"""
parser.add_argument("template", help="Template name, built-in predefined one or user one. "
"You can use built-in templates: cmake_lib, cmake_exe, "
parser.add_argument("template", help="Template name, "
"either a predefined built-in or a user-provided one. "
"Available built-in templates: basic, cmake_lib, cmake_exe, "
"meson_lib, meson_exe, msbuild_lib, msbuild_exe, bazel_lib, bazel_exe, "
"autotools_lib, autotools_exe. "
"E.g. 'conan new cmake_lib -d name=hello -d version=0.1'. "
"You can define your own templates too."
"You can define your own templates too by inputting an absolute path "
"as your template, or a path relative to your conan home folder."
)
parser.add_argument("-d", "--define", action="append",
help="Define a template argument as key=value")
parser.add_argument("-f", "--force", action='store_true', help="Overwrite file if exists")
parser.add_argument("-f", "--force", action='store_true', help="Overwrite file if it already exists")

args = parser.parse_args(*args)
# Manually parsing the remainder
Expand All @@ -34,7 +36,14 @@ def new(conan_api, parser, *args):
except ValueError:
raise ConanException(f"Template definitions must be 'key=value', received {u}")
k = k.replace("-", "") # Remove possible "--name=value"
definitions[k] = v
# For variables that only show up once, no need for list to keep compatible behaviour
if k in definitions:
if isinstance(definitions[k], list):
definitions[k].append(v)
else:
definitions[k] = [definitions[k], v]
else:
definitions[k] = v

files = conan_api.new.get_template(args.template) # First priority: user folder
if not files: # then, try the templates in the Conan home
Expand Down
54 changes: 54 additions & 0 deletions conan/internal/api/new/basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
def inject_get_or_else(variable, default):
AbrilRBS marked this conversation as resolved.
Show resolved Hide resolved
return variable + ' = "{% if ' + variable + " is defined %}{{ " + variable + " }}{% else %}" + default + '{% endif %}"'

_conanfile_header = f'''\
{inject_get_or_else("name", "pkg")}
{inject_get_or_else("version", "1.0")}
{inject_get_or_else("description", "A basic recipe")}
{inject_get_or_else("license", "<Your project license goes here>")}
{inject_get_or_else("homepage", "<Your project homepage goes here>")}
'''

_conanfile = '''\
from conan import ConanFile

class BasicConanfile(ConanFile):
''' + _conanfile_header + '''\

# The requirements method allows you to define the dependencies of your recipe
def requirements(self):
# Each call to self.requires() will add the corresponding requirement
# to the current list of requirements
{% if requires is defined -%}
{% for require in as_iterable(requires) -%}
self.requires("{{ require }}")
{% endfor %}
{% else -%}
# Uncommenting this line will add the zlib/1.2.13 dependency to your project
# self.requires("zlib/1.2.13")
pass
{%- endif %}

# The purpose of generate() is to prepare the build, generating the necessary files, such as
# Files containing information to locate the dependencies, environment activation scripts,
# and specific build system files among others
def generate(self):
pass

# This method is used to build the source code of the recipe using the desired commands.
def build(self):
# You can use your command line tools to invoke your build system
# or any of the build helpers provided with Conan in conan.tools
# self.run("g++ ...")
pass

# The actual creation of the package, once it's built, is done in the package() method.
# Using the copy() method from tools.files, artifacts are copied
# from the build folder to the package folder
def package(self):
# copy(self, "*.h", self.source_folder, join(self.package_folder, "include"), keep_path=False)
pass
'''


basic_file = {"conanfile.py": _conanfile}
14 changes: 14 additions & 0 deletions conans/test/integration/command/new_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ def test_new_missing_definitions(self):
client.run("new cmake_lib -d version=myversion", assert_error=True)
assert "Missing definitions for the template. Required definitions are: 'name', 'version'" in client.out

def test_new_basic_template(self):
tc = TestClient()
try:
tc.run("new basic")
assert '# self.requires("zlib/1.2.13")' in tc.load("conanfile.py")
except Exception as e:
assert False, f"conan new basic should work without any extra arguments: {e}"
AbrilRBS marked this conversation as resolved.
Show resolved Hide resolved

tc.run("new basic -d name=mygame -d requires=math/1.0 -d requires=ai/1.0 -f")
conanfile = tc.load("conanfile.py")
assert 'self.requires("math/1.0")' in conanfile
assert 'self.requires("ai/1.0")' in conanfile
assert 'name = "mygame"' in conanfile


class TestNewCommandUserTemplate:

Expand Down
2 changes: 2 additions & 0 deletions conans/test/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import zipfile
from collections import OrderedDict
from contextlib import contextmanager
from typing import List
AbrilRBS marked this conversation as resolved.
Show resolved Hide resolved
from urllib.parse import urlsplit, urlunsplit

import bottle
Expand Down Expand Up @@ -816,6 +817,7 @@ def search(self, pattern, remote=None, assert_error=False, args=None):
data = json.loads(self.load(".tmp.json"))
return data


AbrilRBS marked this conversation as resolved.
Show resolved Hide resolved
def massive_uploader(self, ref, revisions, num_prev, remote=None):
"""Uploads N revisions with M package revisions. The revisions can be specified like:
revisions = [{"os": "Windows"}, {"os": "Linux"}], \
Expand Down