gibson-cli 0.6.1__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gibson/api/BaseApi.py +2 -1
- gibson/api/Cli.py +9 -2
- gibson/command/Build.py +60 -8
- gibson/command/Help.py +0 -12
- gibson/command/Question.py +4 -7
- gibson/command/code/Code.py +42 -12
- gibson/command/code/Entity.py +25 -7
- gibson/command/code/Model.py +1 -1
- gibson/command/code/Schema.py +1 -1
- gibson/command/code/Test.py +35 -0
- gibson/command/code/Tests.py +12 -21
- gibson/command/importer/Import.py +83 -11
- gibson/command/importer/OpenApi.py +4 -9
- gibson/command/new/Module.py +1 -1
- gibson/command/new/New.py +3 -3
- gibson/command/new/Project.py +2 -2
- gibson/command/rewrite/Rewrite.py +9 -14
- gibson/command/tests/test_command_Conf.py +1 -0
- gibson/conf/Project.py +1 -0
- gibson/core/Configuration.py +21 -58
- gibson/core/Conversation.py +25 -7
- gibson/data/bash-completion.tmpl +3 -4
- gibson/data/postgresql/default-ref-table.tmpl +4 -0
- gibson/data/postgresql/default-table.tmpl +5 -0
- gibson/db/TableExceptions.py +3 -0
- gibson/db/tests/test_db_TableExceptions.py +4 -0
- gibson/services/code/context/schema/EntityKeys.py +3 -3
- gibson/services/code/context/schema/tests/test_code_context_schema_EntityKeys.py +3 -3
- gibson/structure/Entity.py +12 -109
- gibson/structure/mysql/Entity.py +117 -0
- gibson/structure/{constraints → mysql/constraints}/ReferenceConstraint.py +6 -2
- gibson/structure/{keys → mysql/keys}/ForeignKey.py +9 -5
- gibson/structure/{keys → mysql/keys}/Index.py +7 -3
- gibson/structure/{keys/tests/test_ForeignKey.py → mysql/keys/tests/test_structure_mysql_keys_ForeignKey.py} +16 -8
- gibson/structure/{keys/tests/test_Index.py → mysql/keys/tests/test_structure_mysql_keys_Index.py} +7 -3
- gibson/structure/{keys/tests/test_IndexAttribute.py → mysql/keys/tests/test_structure_mysql_keys_IndexAttribute.py} +1 -1
- gibson/structure/mysql/testing.py +231 -0
- gibson/structure/{tests/test_Entity.py → mysql/tests/test_structure_mysql_Entity.py} +34 -20
- gibson/structure/postgresql/Entity.py +108 -0
- gibson/structure/postgresql/References.py +61 -0
- gibson/structure/postgresql/table/ForeignKey.py +28 -0
- gibson/structure/postgresql/table/tests/test_structure_postgresql_table_ForeignKey.py +44 -0
- gibson/structure/{testing.py → postgresql/testing.py} +45 -82
- gibson/structure/postgresql/tests/test_structure_postgresql_Entity.py +82 -0
- gibson/structure/tests/test_structure_Entity.py +22 -0
- {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.0.dist-info}/METADATA +25 -27
- {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.0.dist-info}/RECORD +57 -47
- {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.0.dist-info}/WHEEL +1 -1
- gibson/command/rewrite/Tests.py +0 -26
- /gibson/command/{rewrite → code}/Api.py +0 -0
- /gibson/command/{rewrite → code}/Base.py +0 -0
- /gibson/command/{rewrite → code}/Models.py +0 -0
- /gibson/command/{rewrite → code}/Schemas.py +0 -0
- /gibson/data/{default-ref-table.tmpl → mysql/default-ref-table.tmpl} +0 -0
- /gibson/data/{default-table.tmpl → mysql/default-table.tmpl} +0 -0
- /gibson/structure/{keys → mysql/keys}/IndexAttribute.py +0 -0
- {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.0.dist-info}/entry_points.txt +0 -0
- {gibson_cli-0.6.1.dist-info → gibson_cli-0.7.0.dist-info}/top_level.txt +0 -0
gibson/api/BaseApi.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
import pprint
|
2
3
|
|
3
4
|
import requests
|
4
5
|
|
@@ -96,7 +97,7 @@ class BaseApi:
|
|
96
97
|
message = r.json()
|
97
98
|
print("=" * 78)
|
98
99
|
print("Raw Response:\n")
|
99
|
-
|
100
|
+
pprint.pprint(message)
|
100
101
|
print("\n" + "=" * 78)
|
101
102
|
except requests.exceptions.JSONDecodeError:
|
102
103
|
pass
|
gibson/api/Cli.py
CHANGED
@@ -66,7 +66,10 @@ class Cli(BaseApi):
|
|
66
66
|
|
67
67
|
def headers(self):
|
68
68
|
headers = super().headers()
|
69
|
-
|
69
|
+
if self.configuration.project.id:
|
70
|
+
headers["X-Gibson-Project-ID"] = self.configuration.project.id
|
71
|
+
else:
|
72
|
+
headers["X-Gibson-API-Key"] = self.configuration.project.api.key
|
70
73
|
return headers
|
71
74
|
|
72
75
|
def import_(self):
|
@@ -157,7 +160,11 @@ class Cli(BaseApi):
|
|
157
160
|
def modeler_openapi(self, modeler_version, contents):
|
158
161
|
r = self.post(
|
159
162
|
"modeler/openapi",
|
160
|
-
{
|
163
|
+
{
|
164
|
+
"contents": contents,
|
165
|
+
"datastore": {"type": self.configuration.project.datastore.type},
|
166
|
+
"modeler": {"version": modeler_version},
|
167
|
+
},
|
161
168
|
)
|
162
169
|
|
163
170
|
return r.json()
|
gibson/command/Build.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import sys
|
2
2
|
|
3
|
+
import sqlalchemy
|
3
4
|
from sqlalchemy import create_engine
|
4
5
|
from sqlalchemy.orm import sessionmaker
|
5
6
|
|
@@ -18,11 +19,19 @@ class Build(BaseCommand):
|
|
18
19
|
|
19
20
|
self.conversation.type("Connected to datastore...\n")
|
20
21
|
|
22
|
+
if self.configuration.project.datastore.type == "mysql":
|
23
|
+
self.__build_mysql(session)
|
24
|
+
elif self.configuration.project.datastore.type == "postgresql":
|
25
|
+
self.__build_postgresql(session)
|
26
|
+
|
27
|
+
self.conversation.newline()
|
28
|
+
|
29
|
+
def __build_mysql(self, session):
|
21
30
|
try:
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
31
|
+
table_exceptions = TableExceptions().mysql()
|
32
|
+
|
33
|
+
session.execute("set foreign_key_checks = 0")
|
34
|
+
self.conversation.type(" foreign key checks have been disabled\n")
|
26
35
|
|
27
36
|
tables = session.execute("show tables").all()
|
28
37
|
if len(tables) > 0:
|
@@ -39,11 +48,54 @@ class Build(BaseCommand):
|
|
39
48
|
self.conversation.type(f" {entity['name']}\n", delay=0.002)
|
40
49
|
session.execute(entity["definition"])
|
41
50
|
finally:
|
42
|
-
|
43
|
-
|
44
|
-
|
51
|
+
session.execute("set foreign_key_checks = 1")
|
52
|
+
self.conversation.type(" foreign key checks have been enabled\n")
|
53
|
+
|
54
|
+
def __build_postgresql(self, session):
|
55
|
+
table_exceptions = TableExceptions().postgresql()
|
56
|
+
|
57
|
+
schema = list(session.execute("select current_schema()"))[0][0]
|
58
|
+
self.conversation.type(f" current schema is {schema}\n")
|
59
|
+
|
60
|
+
tables = list(
|
61
|
+
session.execute(
|
62
|
+
"""select table_name
|
63
|
+
from information_schema.tables
|
64
|
+
where table_schema = :table_schema""",
|
65
|
+
{"table_schema": schema},
|
66
|
+
)
|
67
|
+
)
|
45
68
|
|
46
|
-
|
69
|
+
if len(tables) > 0:
|
70
|
+
self.conversation.type(" dropping existing entities\n")
|
71
|
+
|
72
|
+
for table in tables:
|
73
|
+
self.conversation.type(f" {table[0]}\n", delay=0.002)
|
74
|
+
session.execute(f"drop table if exists {schema}.{table[0]} cascade")
|
75
|
+
session.commit()
|
76
|
+
|
77
|
+
self.conversation.type(" building entities\n")
|
78
|
+
|
79
|
+
tables = {}
|
80
|
+
for entity in self.memory.entities:
|
81
|
+
tables[entity["name"]] = entity["definition"]
|
82
|
+
|
83
|
+
while tables != {}:
|
84
|
+
remove = []
|
85
|
+
for name, definition in tables.items():
|
86
|
+
|
87
|
+
try:
|
88
|
+
session.execute(definition)
|
89
|
+
session.commit()
|
90
|
+
|
91
|
+
self.conversation.type(f' {name.split(".")[-1]}\n', delay=0.002)
|
92
|
+
|
93
|
+
remove.append(name)
|
94
|
+
except sqlalchemy.exc.ProgrammingError:
|
95
|
+
session.rollback()
|
96
|
+
|
97
|
+
for name in remove:
|
98
|
+
del tables[name]
|
47
99
|
|
48
100
|
def execute(self):
|
49
101
|
if len(sys.argv) != 3 or sys.argv[2] != "datastore":
|
gibson/command/Help.py
CHANGED
@@ -48,10 +48,6 @@ class Help(BaseCommand):
|
|
48
48
|
"description": "move last changes into project",
|
49
49
|
"memory": "last -> stored",
|
50
50
|
},
|
51
|
-
"model": {
|
52
|
-
"description": "write the model code for an entity",
|
53
|
-
"memory": "stored",
|
54
|
-
},
|
55
51
|
"modify": {
|
56
52
|
"description": "change an entity using natural language",
|
57
53
|
"memory": "last > stored",
|
@@ -69,15 +65,7 @@ class Help(BaseCommand):
|
|
69
65
|
"description": "rewrite code",
|
70
66
|
"memory": "stored",
|
71
67
|
},
|
72
|
-
"schema": {
|
73
|
-
"description": "write the schema code for an entity",
|
74
|
-
"memory": "stored",
|
75
|
-
},
|
76
68
|
"show": {"description": "display an entity", "memory": "last > stored"},
|
77
|
-
"test": {
|
78
|
-
"description": "write the unit tests for an entity",
|
79
|
-
"memory": "stored",
|
80
|
-
},
|
81
69
|
"tree": {"description": "illustrate the project layout", "memory": None},
|
82
70
|
"q": {"description": "ask Gibson a question", "memory": None},
|
83
71
|
}
|
gibson/command/Question.py
CHANGED
@@ -28,7 +28,10 @@ class Question(BaseCommand):
|
|
28
28
|
with open(path, "r") as f:
|
29
29
|
contents = f.read()
|
30
30
|
except FileNotFoundError:
|
31
|
-
self.
|
31
|
+
self.configuration.display_project()
|
32
|
+
self.conversation.file_not_found(path)
|
33
|
+
self.conversation.newline()
|
34
|
+
exit(1)
|
32
35
|
|
33
36
|
has_file = True
|
34
37
|
instructions += f"\n\n{contents}\n\n"
|
@@ -81,12 +84,6 @@ class Question(BaseCommand):
|
|
81
84
|
|
82
85
|
self.conversation.newline()
|
83
86
|
|
84
|
-
def __file_not_found(self, path):
|
85
|
-
self.configuration.display_project()
|
86
|
-
self.conversation.type(f'404, My Friend. Cannot find file "{path}".\n')
|
87
|
-
self.conversation.newline()
|
88
|
-
exit(1)
|
89
|
-
|
90
87
|
def __python_import_not_found(self, import_):
|
91
88
|
self.configuration.display_project()
|
92
89
|
self.conversation.type(f'That\'s a misfire, "{import_}" does not exist.\n')
|
gibson/command/code/Code.py
CHANGED
@@ -2,41 +2,71 @@ import sys
|
|
2
2
|
|
3
3
|
import gibson.core.Colors as Colors
|
4
4
|
from gibson.command.BaseCommand import BaseCommand
|
5
|
-
from gibson.command.code.
|
6
|
-
from gibson.command.code.
|
7
|
-
from gibson.command.code.
|
8
|
-
from gibson.command.code.
|
5
|
+
from gibson.command.code.Api import Api as CodeApi
|
6
|
+
from gibson.command.code.Base import Base as CodeBase
|
7
|
+
from gibson.command.code.Entity import Entity as CodeEntity
|
8
|
+
from gibson.command.code.Model import Model as CodeModel
|
9
|
+
from gibson.command.code.Models import Models as CodeModels
|
10
|
+
from gibson.command.code.Schema import Schema as CodeSchema
|
11
|
+
from gibson.command.code.Schemas import Schemas as CodeSchemas
|
12
|
+
from gibson.command.code.Test import Test as CodeTest
|
13
|
+
from gibson.command.code.Tests import Tests as CodeTests
|
9
14
|
|
10
15
|
|
11
16
|
class Code(BaseCommand):
|
12
17
|
def execute(self):
|
13
|
-
if len(sys.argv) ==
|
18
|
+
if len(sys.argv) == 3 and sys.argv[2] == "api":
|
19
|
+
CodeApi(self.configuration).execute()
|
20
|
+
elif len(sys.argv) == 3 and sys.argv[2] == "base":
|
21
|
+
CodeBase(self.configuration).execute()
|
22
|
+
elif len(sys.argv) == 4 and sys.argv[2] == "entity":
|
14
23
|
CodeEntity(self.configuration).execute()
|
15
|
-
elif len(sys.argv) ==
|
24
|
+
elif len(sys.argv) == 3 and sys.argv[2] == "models":
|
25
|
+
CodeModels(self.configuration).execute()
|
26
|
+
elif len(sys.argv) == 4 and sys.argv[2] == "models":
|
16
27
|
CodeModel(self.configuration).execute()
|
17
|
-
elif len(sys.argv) ==
|
28
|
+
elif len(sys.argv) == 3 and sys.argv[2] == "schemas":
|
29
|
+
CodeSchemas(self.configuration).execute()
|
30
|
+
elif len(sys.argv) == 4 and sys.argv[2] == "schemas":
|
18
31
|
CodeSchema(self.configuration).execute()
|
19
|
-
elif len(sys.argv) ==
|
32
|
+
elif len(sys.argv) == 3 and sys.argv[2] == "tests":
|
20
33
|
CodeTests(self.configuration).execute()
|
34
|
+
elif len(sys.argv) == 4 and sys.argv[2] == "tests":
|
35
|
+
CodeTest(self.configuration).execute()
|
21
36
|
else:
|
22
37
|
self.usage()
|
23
38
|
|
24
39
|
def usage(self):
|
25
40
|
self.configuration.display_project()
|
26
41
|
self.conversation.type(
|
27
|
-
f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.arguments(['entity', '
|
42
|
+
f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.arguments(['api', 'base', 'entity', 'models', 'schemas', 'tests'])} {Colors.input('[entity name]')} {Colors.hint('write code')}\n"
|
43
|
+
)
|
44
|
+
self.conversation.type(
|
45
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('api')} {Colors.hint('generate the API code')}\n"
|
46
|
+
)
|
47
|
+
self.conversation.type(
|
48
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('base')} {Colors.hint('generate the base code')}\n"
|
28
49
|
)
|
29
50
|
self.conversation.type(
|
30
51
|
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('entity')} {Colors.input('[entity name]')} {Colors.hint('create or update an entity using the AI pair programmer')}\n"
|
31
52
|
)
|
32
53
|
self.conversation.type(
|
33
|
-
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('
|
54
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('models')} {Colors.hint('generate the models for all entities')}\n"
|
55
|
+
)
|
56
|
+
self.conversation.type(
|
57
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('models')} {Colors.input('[entity name]')} {Colors.hint('generate the model(s) for a single entity')}\n"
|
58
|
+
)
|
59
|
+
self.conversation.type(
|
60
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('schemas')} {Colors.hint('generate the schemas for all entities')}\n"
|
61
|
+
)
|
62
|
+
self.conversation.type(
|
63
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('schemas')} {Colors.input('[entity name]')} {Colors.hint('generate the schema(s) for a single entity')}\n"
|
34
64
|
)
|
35
65
|
self.conversation.type(
|
36
|
-
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('
|
66
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.hint('generate the unit tests for all entities')}\n"
|
37
67
|
)
|
38
68
|
self.conversation.type(
|
39
|
-
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.input('[entity name]')} {Colors.hint('generate the unit tests for
|
69
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('code')} {Colors.argument('tests')} {Colors.input('[entity name]')} {Colors.hint('generate the unit tests for a single entity')}\n"
|
40
70
|
)
|
41
71
|
self.conversation.newline()
|
42
72
|
exit(1)
|
gibson/command/code/Entity.py
CHANGED
@@ -14,10 +14,10 @@ from gibson.display.WorkspaceHeader import WorkspaceHeader
|
|
14
14
|
from gibson.services.code.context.schema.Manager import (
|
15
15
|
Manager as CodeContextSchemaManager,
|
16
16
|
)
|
17
|
-
from gibson.structure.Entity import Entity
|
17
|
+
from gibson.structure.Entity import Entity as StructureEntity
|
18
18
|
|
19
19
|
|
20
|
-
class
|
20
|
+
class Entity(BaseCommand):
|
21
21
|
CODE_WRITER_ENTITY_MODIFIER_NOOP = ""
|
22
22
|
|
23
23
|
def __init__(self, configuration: Configuration):
|
@@ -96,7 +96,11 @@ class CodeEntity(BaseCommand):
|
|
96
96
|
definition,
|
97
97
|
self.CODE_WRITER_ENTITY_MODIFIER_NOOP,
|
98
98
|
)
|
99
|
-
entity =
|
99
|
+
entity = (
|
100
|
+
StructureEntity()
|
101
|
+
.instantiate(self.configuration.project.datastore.type)
|
102
|
+
.import_from_struct(data)
|
103
|
+
)
|
100
104
|
|
101
105
|
while True:
|
102
106
|
self.__render_workspace(entity, data["code"][0]["definition"])
|
@@ -147,15 +151,29 @@ class CodeEntity(BaseCommand):
|
|
147
151
|
entity.create_statement(),
|
148
152
|
input_,
|
149
153
|
)
|
150
|
-
entity =
|
154
|
+
entity = (
|
155
|
+
StructureEntity()
|
156
|
+
.instantiate(self.configuration.project.datastore.type)
|
157
|
+
.import_from_struct(data)
|
158
|
+
)
|
151
159
|
|
152
160
|
def get_default_ref_table_template_path(self):
|
153
|
-
return
|
161
|
+
return (
|
162
|
+
os.path.dirname(__file__)
|
163
|
+
+ "/../../data/"
|
164
|
+
+ self.configuration.project.datastore.type
|
165
|
+
+ "/default-ref-table.tmpl"
|
166
|
+
)
|
154
167
|
|
155
168
|
def get_default_table_template_path(self):
|
156
|
-
return
|
169
|
+
return (
|
170
|
+
os.path.dirname(__file__)
|
171
|
+
+ "/../../data/"
|
172
|
+
+ self.configuration.project.datastore.type
|
173
|
+
+ "/default-table.tmpl"
|
174
|
+
)
|
157
175
|
|
158
|
-
def __render_workspace(self, entity:
|
176
|
+
def __render_workspace(self, entity: StructureEntity, model):
|
159
177
|
self.configuration.platform.cmd_clear()
|
160
178
|
|
161
179
|
print("")
|
gibson/command/code/Model.py
CHANGED
gibson/command/code/Schema.py
CHANGED
@@ -7,7 +7,7 @@ from gibson.core.TimeKeeper import TimeKeeper
|
|
7
7
|
from gibson.dev.Dev import Dev
|
8
8
|
|
9
9
|
|
10
|
-
class
|
10
|
+
class Schema(BaseCommand):
|
11
11
|
def execute(self):
|
12
12
|
self.configuration.require_project()
|
13
13
|
entity = self.memory.recall_stored_entity(sys.argv[3])
|
@@ -0,0 +1,35 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
import gibson.core.Colors as Colors
|
4
|
+
from gibson.api.Cli import Cli
|
5
|
+
from gibson.command.BaseCommand import BaseCommand
|
6
|
+
from gibson.core.TimeKeeper import TimeKeeper
|
7
|
+
from gibson.dev.Dev import Dev
|
8
|
+
|
9
|
+
|
10
|
+
class Test(BaseCommand):
|
11
|
+
def execute(self):
|
12
|
+
self.configuration.require_project()
|
13
|
+
entity = self.memory.recall_stored_entity(sys.argv[3])
|
14
|
+
if entity is None:
|
15
|
+
self.conversation.not_sure_no_entity(
|
16
|
+
self.configuration.project.name, sys.argv[3]
|
17
|
+
)
|
18
|
+
exit(1)
|
19
|
+
|
20
|
+
time_keeper = TimeKeeper()
|
21
|
+
|
22
|
+
cli = Cli(self.configuration)
|
23
|
+
response = cli.code_testing([entity["name"]])
|
24
|
+
|
25
|
+
Dev(self.configuration).tests(
|
26
|
+
response["code"][0]["entity"]["name"], response["code"][0]["definition"]
|
27
|
+
)
|
28
|
+
|
29
|
+
if self.configuration.project.dev.active is True:
|
30
|
+
self.conversation.type(
|
31
|
+
f"Gibson wrote the following {Colors.argument('tests')} to your project:\n"
|
32
|
+
)
|
33
|
+
|
34
|
+
print(response["code"][0]["definition"])
|
35
|
+
time_keeper.display()
|
gibson/command/code/Tests.py
CHANGED
@@ -1,35 +1,26 @@
|
|
1
|
-
import sys
|
2
|
-
|
3
|
-
import gibson.core.Colors as Colors
|
4
1
|
from gibson.api.Cli import Cli
|
5
2
|
from gibson.command.BaseCommand import BaseCommand
|
6
3
|
from gibson.core.TimeKeeper import TimeKeeper
|
7
4
|
from gibson.dev.Dev import Dev
|
8
5
|
|
9
6
|
|
10
|
-
class
|
7
|
+
class Tests(BaseCommand):
|
11
8
|
def execute(self):
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
self.configuration.project.name, sys.argv[3]
|
17
|
-
)
|
18
|
-
exit(1)
|
9
|
+
entities = []
|
10
|
+
if self.memory.entities is not None:
|
11
|
+
for entity in self.memory.entities:
|
12
|
+
entities.append(entity["name"])
|
19
13
|
|
20
14
|
time_keeper = TimeKeeper()
|
21
15
|
|
22
16
|
cli = Cli(self.configuration)
|
23
|
-
response = cli.code_testing(
|
17
|
+
response = cli.code_testing(entities)
|
24
18
|
|
25
|
-
|
26
|
-
|
27
|
-
)
|
19
|
+
for entry in response["code"]:
|
20
|
+
Dev(self.configuration).tests(entry["entity"]["name"], entry["definition"])
|
28
21
|
|
29
|
-
|
30
|
-
|
31
|
-
f"Gibson wrote the following {Colors.argument('tests')} to your project:\n"
|
32
|
-
)
|
22
|
+
if self.conversation.muted() is False:
|
23
|
+
print(entry["definition"])
|
33
24
|
|
34
|
-
|
35
|
-
|
25
|
+
if self.conversation.muted() is False:
|
26
|
+
time_keeper.display()
|
@@ -1,3 +1,4 @@
|
|
1
|
+
import re
|
1
2
|
import sys
|
2
3
|
|
3
4
|
from sqlalchemy import create_engine
|
@@ -19,8 +20,11 @@ class Import(BaseCommand):
|
|
19
20
|
if len(sys.argv) == 3 and sys.argv[2] == "api":
|
20
21
|
entities = self.__import_from_api()
|
21
22
|
write_code = self.configuration.project.dev.active
|
22
|
-
elif len(sys.argv) == 3 and sys.argv[2] == "
|
23
|
-
entities = self.
|
23
|
+
elif len(sys.argv) == 3 and sys.argv[2] == "mysql":
|
24
|
+
entities = self.__import_from_mysql()()
|
25
|
+
write_code = self.configuration.project.dev.active
|
26
|
+
elif len(sys.argv) == 4 and sys.argv[2] == "pg_dump":
|
27
|
+
entities = self.__import_from_postgresql()
|
24
28
|
write_code = self.configuration.project.dev.active
|
25
29
|
elif len(sys.argv) == 4 and sys.argv[2] == "openapi":
|
26
30
|
return OpenApi(self.configuration).execute()
|
@@ -31,7 +35,10 @@ class Import(BaseCommand):
|
|
31
35
|
|
32
36
|
word_entities = "entity" if len(entities) == 1 else "entities"
|
33
37
|
|
34
|
-
|
38
|
+
if len(entities) > 0:
|
39
|
+
self.conversation.newline()
|
40
|
+
|
41
|
+
self.conversation.type("Summary\n")
|
35
42
|
self.conversation.type(f" {len(entities)} {word_entities} imported\n")
|
36
43
|
self.conversation.newline()
|
37
44
|
|
@@ -53,15 +60,11 @@ class Import(BaseCommand):
|
|
53
60
|
|
54
61
|
return response["project"]["entities"]
|
55
62
|
|
56
|
-
def
|
57
|
-
self.configuration.display_project()
|
58
|
-
|
63
|
+
def __import_from_mysql(self):
|
59
64
|
db = create_engine(self.configuration.project.datastore.uri)
|
60
65
|
session = sessionmaker(autocommit=False, autoflush=False, bind=db)()
|
61
66
|
|
62
|
-
table_exceptions = TableExceptions().
|
63
|
-
if self.configuration.project.datastore.type == "mysql":
|
64
|
-
table_exceptions = TableExceptions().mysql()
|
67
|
+
table_exceptions = TableExceptions().mysql()
|
65
68
|
|
66
69
|
self.conversation.type("Connected to datastore...\n")
|
67
70
|
self.conversation.type("Building schema...\n")
|
@@ -83,6 +86,72 @@ class Import(BaseCommand):
|
|
83
86
|
|
84
87
|
return entities
|
85
88
|
|
89
|
+
def __import_from_postgresql(self):
|
90
|
+
self.conversation.type("Reading pg_dump file...\n")
|
91
|
+
|
92
|
+
try:
|
93
|
+
with open(sys.argv[3], "r") as f:
|
94
|
+
contents = f.read()
|
95
|
+
except FileNotFoundError:
|
96
|
+
self.conversation.file_not_found(sys.argv[3])
|
97
|
+
self.conversation.newline()
|
98
|
+
exit(1)
|
99
|
+
|
100
|
+
lines = contents.split("\n")
|
101
|
+
|
102
|
+
tables = {}
|
103
|
+
for i in range(len(lines)):
|
104
|
+
matches = re.search(
|
105
|
+
r"^create table (.*)\s+\(", lines[i].lstrip().rstrip(), re.IGNORECASE
|
106
|
+
)
|
107
|
+
if matches:
|
108
|
+
table_name = matches[1].split(".")[-1]
|
109
|
+
definition = []
|
110
|
+
|
111
|
+
while True:
|
112
|
+
i += 1
|
113
|
+
|
114
|
+
if lines[i].lstrip().rstrip() == ");":
|
115
|
+
tables[table_name] = definition
|
116
|
+
break
|
117
|
+
else:
|
118
|
+
definition.append(lines[i].lstrip().rstrip())
|
119
|
+
else:
|
120
|
+
matches = re.search(
|
121
|
+
r"^alter table(?:\s+only)\s+(.*)$",
|
122
|
+
lines[i].lstrip().rstrip(),
|
123
|
+
re.IGNORECASE,
|
124
|
+
)
|
125
|
+
if matches:
|
126
|
+
table_name = matches[1].split(".")[-1]
|
127
|
+
|
128
|
+
i += 1
|
129
|
+
matches = re.search(
|
130
|
+
r"^add (constraint .*?);?$",
|
131
|
+
lines[i].lstrip().rstrip(),
|
132
|
+
re.IGNORECASE,
|
133
|
+
)
|
134
|
+
if matches:
|
135
|
+
if tables[table_name][-1][-1] != ",":
|
136
|
+
tables[table_name][-1] += ","
|
137
|
+
|
138
|
+
tables[table_name].append(matches[1] + ",")
|
139
|
+
|
140
|
+
entities = []
|
141
|
+
for table_name, definition in tables.items():
|
142
|
+
self.conversation.type(f" {table_name}\n", delay=0.002)
|
143
|
+
|
144
|
+
definition[-1] = definition[-1].rstrip(",")
|
145
|
+
|
146
|
+
create_table = f"create table if not exists {table_name} (\n"
|
147
|
+
for entry in definition:
|
148
|
+
create_table += " " * 4 + entry + "\n"
|
149
|
+
create_table += ")"
|
150
|
+
|
151
|
+
entities.append({"definition": create_table, "name": table_name})
|
152
|
+
|
153
|
+
return entities
|
154
|
+
|
86
155
|
def usage(self):
|
87
156
|
self.configuration.display_project()
|
88
157
|
datastore_uri = (
|
@@ -91,13 +160,16 @@ class Import(BaseCommand):
|
|
91
160
|
else ""
|
92
161
|
)
|
93
162
|
self.conversation.type(
|
94
|
-
f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.arguments(['api', '
|
163
|
+
f"usage: {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.arguments(['api', 'mysql', 'pg_dump', 'openapi'])} {Colors.hint('import entities')}\n"
|
95
164
|
)
|
96
165
|
self.conversation.type(
|
97
166
|
f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('api')} {Colors.hint(f'import all entities from your project created on {Colors.link(self.configuration.app_domain())}')}\n"
|
98
167
|
)
|
99
168
|
self.conversation.type(
|
100
|
-
f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('
|
169
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('mysql')} {Colors.hint('import all entities from your MySQL database')} ({Colors.link(datastore_uri)})\n"
|
170
|
+
)
|
171
|
+
self.conversation.type(
|
172
|
+
f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('pg_dump')} {Colors.input('path/to/pg_dump.sql')} {Colors.hint('import all entities from a pg_dump file')}\n"
|
101
173
|
)
|
102
174
|
self.conversation.type(
|
103
175
|
f" {Colors.command(self.configuration.command)} {Colors.subcommand('import')} {Colors.argument('openapi')} {Colors.input('path/to/openapi.json')} {Colors.hint('import all entities from an OpenAPI spec file')}\n"
|
@@ -20,7 +20,10 @@ class OpenApi(BaseCommand):
|
|
20
20
|
with open(sys.argv[3], "r") as f:
|
21
21
|
contents = json.loads(f.read())
|
22
22
|
except FileNotFoundError:
|
23
|
-
self.
|
23
|
+
self.configuration.display_project()
|
24
|
+
self.conversation.file_not_found(sys.argv[3])
|
25
|
+
self.conversation.newline()
|
26
|
+
exit(1)
|
24
27
|
except json.decoder.JSONDecodeError:
|
25
28
|
self.bad_json()
|
26
29
|
|
@@ -112,14 +115,6 @@ class OpenApi(BaseCommand):
|
|
112
115
|
|
113
116
|
return True
|
114
117
|
|
115
|
-
def file_not_found(self):
|
116
|
-
self.configuration.display_project()
|
117
|
-
self.conversation.type(
|
118
|
-
f'Well that embarrassing. There is no file "{sys.argv[3]}".\n'
|
119
|
-
)
|
120
|
-
self.conversation.newline()
|
121
|
-
exit(1)
|
122
|
-
|
123
118
|
def unrecognized_format(self):
|
124
119
|
self.configuration.display_project()
|
125
120
|
self.conversation.type(
|
gibson/command/new/Module.py
CHANGED
gibson/command/new/New.py
CHANGED
@@ -2,9 +2,9 @@ import sys
|
|
2
2
|
|
3
3
|
import gibson.core.Colors as Colors
|
4
4
|
from gibson.command.BaseCommand import BaseCommand
|
5
|
-
from gibson.command.code.Entity import CodeEntity
|
6
|
-
from gibson.command.new.Module import NewModule
|
7
|
-
from gibson.command.new.Project import NewProject
|
5
|
+
from gibson.command.code.Entity import Entity as CodeEntity
|
6
|
+
from gibson.command.new.Module import Module as NewModule
|
7
|
+
from gibson.command.new.Project import Project as NewProject
|
8
8
|
|
9
9
|
|
10
10
|
class New(BaseCommand):
|
gibson/command/new/Project.py
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
from gibson.command.BaseCommand import BaseCommand
|
2
2
|
|
3
3
|
|
4
|
-
class
|
4
|
+
class Project(BaseCommand):
|
5
5
|
def execute(self):
|
6
6
|
self.conversation.new_project(self.configuration)
|
7
7
|
project_name = self.conversation.prompt_project()
|
@@ -9,7 +9,7 @@ class NewProject(BaseCommand):
|
|
9
9
|
self.conversation.project_already_exists(project_name)
|
10
10
|
exit(1)
|
11
11
|
|
12
|
-
project_description = self.conversation.
|
12
|
+
project_description = self.conversation.prompt_project_description(project_name)
|
13
13
|
|
14
14
|
self.configuration.set_project_env(project_name)
|
15
15
|
self.configuration.append_project_to_conf(project_name, project_description)
|