Skip to content

Commit d36fd75

Browse files
committed
Added creating new project to a specific directory
1 parent 682adf1 commit d36fd75

3 files changed

Lines changed: 129 additions & 16 deletions

File tree

ellar_cli/file_scaffolding.py

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import typing as t
33
from abc import abstractmethod
4+
from pathlib import Path
45

56
from jinja2 import Environment
67

@@ -27,16 +28,21 @@ def __init__(
2728
working_directory: str,
2829
scaffold_ellar_template_root_path: str,
2930
ellar_cli_service: t.Optional[EllarCLIService] = None,
31+
specified_directory: str = None,
3032
) -> None:
33+
self._specified_directory = specified_directory
3134
self._schema = schema
32-
self._working_project_name = working_project_name
33-
self._ctx = ProjectScaffoldContext(
34-
Environment(), **self.get_scaffolding_context(working_project_name)
35-
)
36-
self._working_directory = working_directory
35+
self._ctx = ProjectScaffoldContext(Environment())
3736
self._scaffold_ellar_template_root_path = scaffold_ellar_template_root_path
3837
self.ellar_cli_service = ellar_cli_service
39-
self.validate_project_name()
38+
39+
if self._specified_directory:
40+
_cwd_path = Path(self._get_working_cwd(working_directory))
41+
self._working_project_name = _cwd_path.name
42+
self._working_directory = str(_cwd_path.parent)
43+
else:
44+
self._working_directory = working_directory
45+
self._working_project_name = working_project_name
4046

4147
def get_scaffolding_context(self, working_project_name: str) -> t.Dict:
4248
return {}
@@ -61,6 +67,8 @@ def create_file(self, base_path: str, file_name: str, content: t.Any) -> None:
6167
fw.writelines(refined_content)
6268

6369
def scaffold(self) -> None:
70+
self.validate_project_name()
71+
self._ctx = self.get_templating_context()
6472
self.on_scaffold_started()
6573
for file in self._schema.files:
6674
self.create_directory(
@@ -108,3 +116,22 @@ def create_directory(
108116
def validate_project_name(self) -> None:
109117
# Check it's a valid directory name.
110118
pass
119+
120+
def _get_working_cwd(self, working_directory: str) -> str:
121+
if self._specified_directory:
122+
return self._handle_directory_change(working_directory)
123+
return working_directory
124+
125+
def _handle_directory_change(self, working_directory: str) -> str:
126+
if self._specified_directory == ".":
127+
return working_directory
128+
129+
_specified_directory = (
130+
self._specified_directory.lower() # type:ignore[union-attr]
131+
)
132+
return os.path.join(working_directory, _specified_directory)
133+
134+
def get_templating_context(self) -> ProjectScaffoldContext:
135+
return ProjectScaffoldContext(
136+
Environment(), **self.get_scaffolding_context(self._working_project_name)
137+
)

ellar_cli/manage_commands/new.py

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ class NewTemplateScaffold(FileTemplateScaffold):
2424
unwanted_chars = "".join(["-", ";", "!", "*", ":", " "])
2525

2626
def __init__(self, project_name: str = None, **kwargs: t.Any) -> None:
27+
super(NewTemplateScaffold, self).__init__(
28+
working_project_name=project_name, **kwargs
29+
)
2730
self._project_name = project_name
28-
super(NewTemplateScaffold, self).__init__(**kwargs)
2931

3032
def on_scaffold_completed(self) -> None:
3133
popen_res = subprocess.run(
@@ -36,9 +38,18 @@ def on_scaffold_completed(self) -> None:
3638
)
3739
if popen_res.returncode == 0:
3840
project_working_project_name = self.get_project_name()
41+
42+
log_1 = f"- cd {self._working_project_name}"
43+
if self._specified_directory:
44+
log_1 = (
45+
f"- cd {self._specified_directory.lower()}"
46+
if self._specified_directory != "."
47+
else ""
48+
)
49+
3950
print(
40-
f"`{self._working_project_name}` project created successfully.\n"
41-
f"- cd {self._working_project_name}"
51+
f"`{project_working_project_name}` project created successfully.\n"
52+
f"{log_1}"
4253
)
4354
print("To start your server, run the command below")
4455
print(
@@ -47,13 +58,35 @@ def on_scaffold_completed(self) -> None:
4758
else:
4859
print(popen_res.stderr.decode("utf8"))
4960

61+
def is_directory_empty(self) -> bool:
62+
"""
63+
Check if the given directory is empty.
64+
"""
65+
# Get the list of files and directories in the directory
66+
working_project_dir = os.path.join(
67+
self._working_directory, self._working_project_name
68+
)
69+
if os.path.isdir(working_project_dir):
70+
items = os.listdir(working_project_dir)
71+
return len(items) == 0
72+
return True
73+
5074
def validate_project_name(self) -> None:
5175
if os.path.exists(self._working_project_name):
5276
message = "A folder with same name exist '{name}' ".format(
5377
name=self._working_project_name
5478
)
5579
raise EllarCLIException(message)
5680

81+
if not self.is_directory_empty():
82+
working_project_dir = os.path.join(
83+
self._working_directory, self._working_project_name
84+
)
85+
message = (
86+
f"Scaffolding Project Directory is not empty. - {working_project_dir}"
87+
)
88+
raise EllarCLIException(message)
89+
5790
project_working_project_name = self.get_project_name()
5891
if not project_working_project_name.isidentifier():
5992
message = (
@@ -78,10 +111,14 @@ def get_project_cwd(self) -> str:
78111

79112

80113
def new_command(
81-
folder_name: str,
82-
project_name: t.Optional[str] = typer.Option(
114+
project_name: str = typer.Argument(
115+
None,
116+
help="Project Module Name. Defaults to `project-name` if not set",
117+
show_default=False,
118+
),
119+
directory: t.Optional[str] = typer.Argument(
83120
None,
84-
help="Project Module Name. Defaults to `folder-name` if not set",
121+
help="The name of a new directory to scaffold the project into. Scaffolding into an existing directory is only allowed if the directory is empty",
85122
show_default=False,
86123
),
87124
):
@@ -91,7 +128,7 @@ def new_command(
91128
schema=schema,
92129
working_directory=os.getcwd(),
93130
scaffold_ellar_template_root_path=root_scaffold_template_path,
94-
working_project_name=folder_name.lower(),
95131
project_name=project_name,
132+
specified_directory=directory,
96133
)
97134
init_template_scaffold.scaffold()

tests/test_ellar_commands/test_new_command.py

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def test_new_command_works(tmpdir, process_runner):
99
result = process_runner(["ellar", "new", "ellar-project-new"])
1010
assert result.returncode == 0
1111
assert result.stdout.decode("utf8") == (
12-
"`ellar-project-new` project created successfully.\n"
12+
"`ellar_project_new` project created successfully.\n"
1313
"- cd ellar-project-new\n"
1414
"To start your server, run the command below\n"
1515
"- ellar --project ellar_project_new runserver --reload\n"
@@ -26,6 +26,55 @@ def test_new_command_works(tmpdir, process_runner):
2626
}
2727

2828

29+
def test_new_command_works_with_specific_directory(tmpdir, process_runner):
30+
result = process_runner(["ellar", "new", "ellar-project-new", "Another/me"])
31+
assert result.returncode == 0
32+
assert result.stdout.decode("utf8") == (
33+
"`ellar_project_new` project created successfully.\n"
34+
"- cd another/me\n"
35+
"To start your server, run the command below\n"
36+
"- ellar --project ellar_project_new runserver --reload\n"
37+
"Happy coding!\n"
38+
)
39+
os.chdir(os.path.join(tmpdir / "another/me"))
40+
ellar_cli_service = EllarCLIService.import_project_meta()
41+
assert ellar_cli_service._meta.dict() == {
42+
"project_name": "ellar_project_new",
43+
"application": "ellar_project_new.server:application",
44+
"config": "ellar_project_new.config:DevelopmentConfig",
45+
"root_module": "ellar_project_new.root_module:ApplicationModule",
46+
"apps_module": "ellar_project_new.apps",
47+
}
48+
49+
50+
def test_new_command_fails_case_1(tmpdir, process_runner):
51+
result = process_runner(["ellar", "new", "ellar-project-new", "Another/me"])
52+
assert result.returncode == 0
53+
result = process_runner(["ellar", "new", "ellar-project-new", "Another/me"])
54+
assert result.returncode == 1
55+
assert "Scaffolding Project Directory is not empty." in result.stderr.decode("utf8")
56+
57+
58+
def test_new_command_works_with_specific_directory_case_2(tmpdir, process_runner):
59+
result = process_runner(["ellar", "new", "ellar-project-new", "."])
60+
assert result.returncode == 0
61+
assert result.stdout.decode("utf8") == (
62+
"`ellar_project_new` project created successfully.\n\n"
63+
"To start your server, run the command below\n"
64+
"- ellar --project ellar_project_new runserver --reload\n"
65+
"Happy coding!\n"
66+
)
67+
os.chdir(os.path.join(tmpdir))
68+
ellar_cli_service = EllarCLIService.import_project_meta()
69+
assert ellar_cli_service._meta.dict() == {
70+
"project_name": "ellar_project_new",
71+
"application": "ellar_project_new.server:application",
72+
"config": "ellar_project_new.config:DevelopmentConfig",
73+
"root_module": "ellar_project_new.root_module:ApplicationModule",
74+
"apps_module": "ellar_project_new.apps",
75+
}
76+
77+
2978
def test_new_command_fails_for_existing_folder_name(tmp_path, process_runner):
3079
os.makedirs(tmp_path / "ellar-project-exist", exist_ok=True)
3180
result = process_runner(["ellar", "new", "ellar-project-exist"])
@@ -49,7 +98,7 @@ def test_new_template_scaffold_get_project_name():
4998
schema=EllarScaffoldSchema.schema_example(),
5099
working_directory=os.getcwd(),
51100
scaffold_ellar_template_root_path="",
52-
working_project_name="folder-name".lower(),
101+
project_name="folder-name".lower(),
53102
)
54103
assert init_template_scaffold.get_project_name() == "folder_name"
55104
init_template_scaffold._project_name = "folder-name!;-:*"
@@ -62,6 +111,6 @@ def test_new_template_scaffold_get_project_cwd():
62111
schema=EllarScaffoldSchema.schema_example(),
63112
working_directory="working-directory",
64113
scaffold_ellar_template_root_path="",
65-
working_project_name="folder-name".lower(),
114+
project_name="folder-name".lower(),
66115
)
67116
assert init_template_scaffold.get_project_cwd() == "working-directory/folder-name"

0 commit comments

Comments
 (0)