ara-cli 0.1.4.30__tar.gz
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.
- ara_cli-0.1.4.30/MANIFEST.in +1 -0
- ara_cli-0.1.4.30/PKG-INFO +3 -0
- ara_cli-0.1.4.30/README.md +67 -0
- ara_cli-0.1.4.30/ara_cli/__init__.py +1 -0
- ara_cli-0.1.4.30/ara_cli/__main__.py +259 -0
- ara_cli-0.1.4.30/ara_cli/ara_config.py +52 -0
- ara_cli-0.1.4.30/ara_cli/artefact.py +47 -0
- ara_cli-0.1.4.30/ara_cli/artefact_creator.py +120 -0
- ara_cli-0.1.4.30/ara_cli/artefact_deleter.py +42 -0
- ara_cli-0.1.4.30/ara_cli/artefact_link_updater.py +72 -0
- ara_cli-0.1.4.30/ara_cli/artefact_lister.py +17 -0
- ara_cli-0.1.4.30/ara_cli/artefact_renamer.py +86 -0
- ara_cli-0.1.4.30/ara_cli/chat.py +93 -0
- ara_cli-0.1.4.30/ara_cli/classifier.py +60 -0
- ara_cli-0.1.4.30/ara_cli/classifier_validator.py +4 -0
- ara_cli-0.1.4.30/ara_cli/directory_navigator.py +62 -0
- ara_cli-0.1.4.30/ara_cli/file_classifier.py +32 -0
- ara_cli-0.1.4.30/ara_cli/file_lister.py +31 -0
- ara_cli-0.1.4.30/ara_cli/filename_validator.py +4 -0
- ara_cli-0.1.4.30/ara_cli/prompt_extractor.py +130 -0
- ara_cli-0.1.4.30/ara_cli/prompt_handler.py +370 -0
- ara_cli-0.1.4.30/ara_cli/run_file_lister.py +72 -0
- ara_cli-0.1.4.30/ara_cli/template_manager.py +155 -0
- ara_cli-0.1.4.30/ara_cli/templates/agile.artefacts +171 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_businessgoal.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_capability.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_epic.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_feature.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_keyfeature.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_task.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_userstory.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/commands/template_vision.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_businessgoal.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_capability.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_epic.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_feature.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_keyfeature.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_task.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_userstory.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/prompts/template_vision.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_businessgoal.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_capability.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_epic.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_feature.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_keyfeature.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_task.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_userstory.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-creation/rules/template_vision.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_classification_commands.md +9 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_extension_commands.md +17 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_artefact_formulation_commands.md +14 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_code_generation_complex_commands.md +20 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_code_generation_simple_commands.md +13 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_empty_commands.md +14 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_error_fixing_commands.md +20 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_refactoring_analysis_commands.md +9 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/commands/template_refactoring_commands.md +15 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_classify_task_intention_and_context.md +6 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_empty_intention_and_context.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_extend_feature_and_implementation_intention_and_context.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_feature_scenario_adaption_intention_and_context.md +8 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_feature_scenario_implementation_intention_and_context.md +5 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_cli_implementation_with_test_intention_and_context.md +6 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_code_understanding_intention_and_context.md +18 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_error_fixing_intention_and_context.md +9 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/prompts/template_python_implementation_from_task_description_intention_and_context.md +4 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_empty_rules.md +2 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_error_analysis_expert_rules.md +14 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_product_owner_rules.md +22 -0
- ara_cli-0.1.4.30/ara_cli/templates/prompt-modules/rules/template_python_expert_developer_rules.md +8 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.concept.md +27 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.concept_exploration.md +76 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.customer.md +30 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.customer_exploration.md +62 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.persona.md +71 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.persona_exploration.md +106 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.step.md +43 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.step_exploration.md +0 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.technology.md +23 -0
- ara_cli-0.1.4.30/ara_cli/templates/specification_breakdown_files/template.technology_exploration.md +77 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.businessgoal +10 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.businessgoal_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.capability +10 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.capability_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.epic +15 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.epic_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.example +6 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.example_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.feature +25 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.feature_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.issue +14 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.keyfeature +15 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.keyfeature_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.steps_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.task +8 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.task_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.userstory +17 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.userstory_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.vision +14 -0
- ara_cli-0.1.4.30/ara_cli/templates/template.vision_exploration.md +7 -0
- ara_cli-0.1.4.30/ara_cli/tests/__init__.py +0 -0
- ara_cli-0.1.4.30/ara_cli/tests/test_artefact_link_updater.py +56 -0
- ara_cli-0.1.4.30/ara_cli/tests/test_artefact_renamer.py +116 -0
- ara_cli-0.1.4.30/ara_cli/tests/test_directory_navigator.py +13 -0
- ara_cli-0.1.4.30/ara_cli/tests/test_file_creator.py +108 -0
- ara_cli-0.1.4.30/ara_cli/tests/test_template_manager.py +118 -0
- ara_cli-0.1.4.30/ara_cli/vectorDB.py +203 -0
- ara_cli-0.1.4.30/ara_cli/version.py +2 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/PKG-INFO +3 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/SOURCES.txt +114 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/dependency_links.txt +1 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/entry_points.txt +3 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/requires.txt +6 -0
- ara_cli-0.1.4.30/ara_cli.egg-info/top_level.txt +1 -0
- ara_cli-0.1.4.30/setup.cfg +4 -0
- ara_cli-0.1.4.30/setup.py +30 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
recursive-include ara_cli/templates *
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
- [ara-tool](#ara-tool)
|
|
2
|
+
- [best practices commit and merge and recreate workspace](#best-practices-commit-and-merge-and-recreate-workspace)
|
|
3
|
+
- [test and run during development](#test-and-run-during-development)
|
|
4
|
+
- [set version and build and install locally for testing outside of container](#set-version-and-build-and-install-locally-for-testing-outside-of-container)
|
|
5
|
+
- [upload to test pypi with test pypi API key](#upload-to-test-pypi-with-test-pypi-api-key)
|
|
6
|
+
- [upload to live pypi with talsen team production API key (from main branch)](#upload-to-live-pypi-with-talsen-team-production-api-key-from-main-branch)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ara-tool
|
|
10
|
+
## best practices commit and merge and recreate workspace
|
|
11
|
+
1. commit and publish everything in the branch
|
|
12
|
+
2. go to git and merge
|
|
13
|
+
3. destroy old workspace from merged branch from within the working directory
|
|
14
|
+
> workspace destroy
|
|
15
|
+
4. go back in to top level working directory and check which repos are available for branching
|
|
16
|
+
> workspace repos
|
|
17
|
+
5. create new workspacce with workspace command: workspace new <repo> <new-workspace-name>
|
|
18
|
+
> workspace new ara-cmd hans-ara-cmd
|
|
19
|
+
6. switch to new workspace
|
|
20
|
+
|
|
21
|
+
## test and run during development
|
|
22
|
+
1. run `bash deploy.sh`
|
|
23
|
+
2. run `bash login.sh`
|
|
24
|
+
3. --> in container --> for behave BDD tests `bash test-feature.sh`
|
|
25
|
+
3. a) --> in container --> for only 1 test: behave ara/features/<name>.feature
|
|
26
|
+
3. b) --> in container --> for unit tests and (if successful) feature tests: `bash test-all.sh`
|
|
27
|
+
4. --> in container --> for unit tests in folder ara_cli `pytest --cov=. --cov-report term-missing tests/ `
|
|
28
|
+
5. --> in container --> example for running a single unit test in ara_cli folder `pytest tests/test_template_manager.py::test_files_created_from_template`
|
|
29
|
+
6. if change is successfull always commit before proceeding with next change
|
|
30
|
+
7. if change was successfully reviewd merge in gitlab: https://git.talsen.team/talsen-products/ara-tool/-/merge_requests/new
|
|
31
|
+
|
|
32
|
+
## set version and build and install locally for testing outside of container
|
|
33
|
+
1. set the new verion in the ara_cli/version.py file
|
|
34
|
+
2. adapt the version number in the 'local_install.sh' file
|
|
35
|
+
3. use `bash local_install.sh` to control local setup procedure
|
|
36
|
+
4. Test the functionality
|
|
37
|
+
|
|
38
|
+
## upload to test pypi with test pypi API key
|
|
39
|
+
1. run `bash deploy.sh`
|
|
40
|
+
2. run `login.sh`
|
|
41
|
+
3. in `setup.py` and `local_install.sh` increment `version` otherwise upload will fail!
|
|
42
|
+
3. a) merge to staging and continue from a new workspace
|
|
43
|
+
4. from inside container run `python setup.py sdist bdist_wheel`
|
|
44
|
+
5. run the following command:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
twine upload --repository testpypi dist/* --verbose -u __token__ -p pypi-AgENdGVzdC5weXBpLm9yZwIkZGI5YzUyZTUtNDhjMy00NmI3LTgxNmMtY2QwMTRjYjZmZjlmAAIqWzMsImM3ZTM0MDRmLWU1MzUtNDliMi05ZDhiLWQ0NGUyNzlmYTU0MiJdAAAGID-dX7aQZZimTyUQeKPzbP0TlqMEpLQlzRW7VJr1JKab
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
this will upload to a test pypi account.
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
6. run `python3 -m pip install --index-url https://test.pypi.org/simple/ ara_cli==<VERSION>`
|
|
54
|
+
7. run `ara -h`
|
|
55
|
+
8. if everything has worked (upload, installation and usage) you can now continue to upload the package to pypi (live)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
## upload to live pypi with talsen team production API key (from main branch)
|
|
59
|
+
1. run `bash deploy.sh`
|
|
60
|
+
2. run `login.sh`
|
|
61
|
+
3. `dist` folder should still be there from the testupload (otherwise do `python setup.py sdist bdist_wheel` inside the container again), do NOT upload to live without previously testing in test pypi!
|
|
62
|
+
4. Get the API-Key from [nextcloud](https://cloud.talsen.team/apps/keeweb/?open=%2Finfrastructure%2Fpublic-services%2Fapi-keys.kdbx)
|
|
63
|
+
5. Get the Password from Hans or DevOps
|
|
64
|
+
6. run the following command:
|
|
65
|
+
```bash
|
|
66
|
+
twine upload dist/* --verbose -u __token__ -p <API-Key>
|
|
67
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .version import __version__
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from os.path import join, dirname
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
import argparse
|
|
5
|
+
from ara_cli.version import __version__
|
|
6
|
+
from ara_cli.artefact_creator import ArtefactCreator
|
|
7
|
+
from ara_cli.artefact_renamer import ArtefactRenamer
|
|
8
|
+
from ara_cli.classifier import Classifier
|
|
9
|
+
from ara_cli.filename_validator import is_valid_filename
|
|
10
|
+
from ara_cli.classifier_validator import is_valid_classifier
|
|
11
|
+
from ara_cli.template_manager import SpecificationBreakdownAspects, TemplatePathManager
|
|
12
|
+
from ara_cli.artefact_deleter import ArtefactDeleter
|
|
13
|
+
from ara_cli.artefact_lister import ArtefactLister
|
|
14
|
+
from ara_cli.vectorDB import create_DB, add_paths, reset_config, reset_DB, search_DB, update_DB
|
|
15
|
+
from ara_cli.prompt_handler import read_prompt, send_prompt, append_headings, write_prompt_result, default_prompt_creation, initialize_prompt_templates, load_selected_prompt_templates, create_and_send_custom_prompt
|
|
16
|
+
from ara_cli.prompt_extractor import extract_and_save_prompt_results
|
|
17
|
+
|
|
18
|
+
from ara_cli.chat import Chat
|
|
19
|
+
|
|
20
|
+
def check_validity(condition, error_message):
|
|
21
|
+
if not condition:
|
|
22
|
+
print(error_message)
|
|
23
|
+
sys.exit(1)
|
|
24
|
+
|
|
25
|
+
def create_action(args):
|
|
26
|
+
if args.parameter and args.classifier and args.aspect:
|
|
27
|
+
sba = SpecificationBreakdownAspects()
|
|
28
|
+
try:
|
|
29
|
+
sba.create(args.parameter, args.classifier, args.aspect)
|
|
30
|
+
except ValueError as ve:
|
|
31
|
+
print(f"Error: {ve}")
|
|
32
|
+
sys.exit(1)
|
|
33
|
+
|
|
34
|
+
check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
|
|
35
|
+
check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
36
|
+
|
|
37
|
+
template_path = join(dirname(__file__), 'templates')
|
|
38
|
+
artefact_creator = ArtefactCreator()
|
|
39
|
+
artefact_creator.run(args.parameter, args.classifier, template_path)
|
|
40
|
+
|
|
41
|
+
def delete_action(args):
|
|
42
|
+
artefact_deleter = ArtefactDeleter()
|
|
43
|
+
artefact_deleter.delete(args.parameter, args.classifier)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def rename_action(args):
|
|
47
|
+
check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
|
|
48
|
+
check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
49
|
+
check_validity(is_valid_filename(args.aspect), "Invalid new filename provided. Please provide a valid filename.")
|
|
50
|
+
|
|
51
|
+
artefact_renamer = ArtefactRenamer()
|
|
52
|
+
artefact_renamer.rename(args.parameter, args.aspect, args.classifier)
|
|
53
|
+
|
|
54
|
+
def list_action(args):
|
|
55
|
+
artefact_lister = ArtefactLister()
|
|
56
|
+
if args.tags:
|
|
57
|
+
artefact_lister.list_files(tags=args.tags)
|
|
58
|
+
else:
|
|
59
|
+
artefact_lister.list_files()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def prompt_action(args):
|
|
63
|
+
check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
64
|
+
check_validity(is_valid_filename(args.parameter), "Invalid filename provided. Please provide a valid filename.")
|
|
65
|
+
|
|
66
|
+
classifier = args.classifier
|
|
67
|
+
param = args.parameter
|
|
68
|
+
init = args.init
|
|
69
|
+
|
|
70
|
+
if (init == 'init'):
|
|
71
|
+
initialize_prompt_templates(classifier, param)
|
|
72
|
+
elif (init == 'load'):
|
|
73
|
+
load_selected_prompt_templates(classifier, param)
|
|
74
|
+
elif (init == 'send'):
|
|
75
|
+
create_and_send_custom_prompt(classifier, param) # Use the new method when the 'send' command is used
|
|
76
|
+
elif (init == 'extract'):
|
|
77
|
+
extract_and_save_prompt_results(classifier, param) # Use the new method when the 'send' command is used
|
|
78
|
+
|
|
79
|
+
else: # default rules.md, givens.md, prompt.md and commands.md files are used
|
|
80
|
+
default_prompt_creation(classifier, param)
|
|
81
|
+
prompt = read_prompt(classifier, param)
|
|
82
|
+
|
|
83
|
+
if(prompt):
|
|
84
|
+
append_headings(classifier, param, "prompt")
|
|
85
|
+
write_prompt_result(classifier, param, prompt)
|
|
86
|
+
|
|
87
|
+
response = send_prompt(prompt)
|
|
88
|
+
append_headings(classifier, param, "result")
|
|
89
|
+
write_prompt_result(classifier, param, response)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def chat_action(args):
|
|
93
|
+
if args.name:
|
|
94
|
+
# Start or continue specific chat
|
|
95
|
+
chat_name = args.name
|
|
96
|
+
else:
|
|
97
|
+
# Start or continue default chat
|
|
98
|
+
chat_name = "chat"
|
|
99
|
+
chat = Chat(chat_name)
|
|
100
|
+
chat.start()
|
|
101
|
+
|
|
102
|
+
def vector_action(args):
|
|
103
|
+
match args.vector_command:
|
|
104
|
+
case 'init':
|
|
105
|
+
create_DB()
|
|
106
|
+
|
|
107
|
+
case 'update':
|
|
108
|
+
if args.path:
|
|
109
|
+
add_paths(args.path)
|
|
110
|
+
if not args.path:
|
|
111
|
+
update_DB()
|
|
112
|
+
|
|
113
|
+
case 'reset':
|
|
114
|
+
if args.config:
|
|
115
|
+
reset_config()
|
|
116
|
+
if not args.config:
|
|
117
|
+
reset_DB()
|
|
118
|
+
|
|
119
|
+
case 'search':
|
|
120
|
+
search_DB(args.amount, args.user_input)
|
|
121
|
+
|
|
122
|
+
def template_action(args):
|
|
123
|
+
check_validity(is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
124
|
+
check_validity(Classifier.is_valid_classifier(args.classifier), "Invalid classifier provided. Please provide a valid classifier.")
|
|
125
|
+
|
|
126
|
+
template_manager = TemplatePathManager()
|
|
127
|
+
content = template_manager.get_template_content(args.classifier)
|
|
128
|
+
|
|
129
|
+
def handle_invalid_action(args):
|
|
130
|
+
sys.exit("Invalid action provided. Type ara -h for help")
|
|
131
|
+
|
|
132
|
+
def create_parser(subparsers):
|
|
133
|
+
create_parser = subparsers.add_parser("create", help="Create a file with a classifier and aspect")
|
|
134
|
+
create_parser.add_argument("parameter", help="Filename for create action")
|
|
135
|
+
create_parser.add_argument("classifier", help="Classifier for the file to be created")
|
|
136
|
+
create_parser.add_argument("aspect", help="Specification breakdown aspect", nargs='?', default=None)
|
|
137
|
+
|
|
138
|
+
def delete_parser(subparsers):
|
|
139
|
+
delete_parser = subparsers.add_parser("delete", help="Delete a file with a classifier")
|
|
140
|
+
delete_parser.add_argument("parameter", help="Filename for delete action")
|
|
141
|
+
delete_parser.add_argument("classifier", help="Classifier for the file to be deleted")
|
|
142
|
+
|
|
143
|
+
def rename_parser(subparsers):
|
|
144
|
+
rename_parser = subparsers.add_parser("rename", help="Rename a file with a classifier and new filename")
|
|
145
|
+
rename_parser.add_argument("parameter", help="Current filename for rename action")
|
|
146
|
+
rename_parser.add_argument("classifier", help="Classifier for the file to be renamed")
|
|
147
|
+
rename_parser.add_argument("aspect", help="New filename for the file")
|
|
148
|
+
|
|
149
|
+
def list_parser(subparsers):
|
|
150
|
+
list_parser = subparsers.add_parser("list", help="List files with optional tags")
|
|
151
|
+
list_parser.add_argument("tags", nargs="*", help="Tags for listing files")
|
|
152
|
+
|
|
153
|
+
def prompt_parser(subparsers):
|
|
154
|
+
prompt_parser = subparsers.add_parser("prompt", help="Creates a prompt and sends it to ChatGPT and save the result")
|
|
155
|
+
prompt_parser.add_argument("parameter", help="Filename for prompt action")
|
|
156
|
+
prompt_parser.add_argument("classifier", help="Classifier for the file to be prompted")
|
|
157
|
+
prompt_parser.add_argument("init", help="initialize | load | send the prompt template config selection file in the prompt directory", nargs='?', default=None)
|
|
158
|
+
|
|
159
|
+
def vector_init_parser(vector_subparsers):
|
|
160
|
+
init_parser = vector_subparsers.add_parser("init", help="Initialize vectorDB")
|
|
161
|
+
|
|
162
|
+
def vector_update_parser(vector_subparsers):
|
|
163
|
+
update_parser = vector_subparsers.add_parser("update", help="Update vectorDB")
|
|
164
|
+
update_parser.add_argument("path", nargs='*', help="Path(s) to add to config file", default=None)
|
|
165
|
+
|
|
166
|
+
def vector_reset_parser(vector_subparsers):
|
|
167
|
+
reset_parser = vector_subparsers.add_parser("reset", help="Reset vectorDB")
|
|
168
|
+
reset_parser.add_argument("config", nargs="?", help="Optional config to reset", default=None)
|
|
169
|
+
|
|
170
|
+
def vector_search_parser(vector_subparsers):
|
|
171
|
+
search_parser = vector_subparsers.add_parser("search", help="Search vectorDB")
|
|
172
|
+
search_parser.add_argument("amount", nargs="?", help="Amount of paths to return from search", default=4, type=int)
|
|
173
|
+
search_parser.add_argument("user_input", help="Required query to be executed on vectorDB")
|
|
174
|
+
|
|
175
|
+
def vector_parser(subparsers):
|
|
176
|
+
vector_parser = subparsers.add_parser("vector")
|
|
177
|
+
vector_subparsers = vector_parser.add_subparsers(dest='vector_command')
|
|
178
|
+
|
|
179
|
+
vector_init_parser(vector_subparsers)
|
|
180
|
+
vector_update_parser(vector_subparsers)
|
|
181
|
+
vector_reset_parser(vector_subparsers)
|
|
182
|
+
vector_search_parser(vector_subparsers)
|
|
183
|
+
|
|
184
|
+
def chat_parser(subparsers):
|
|
185
|
+
chat_parser = subparsers.add_parser("chat", help="Command line chatbot")
|
|
186
|
+
chat_parser.add_argument("name", help="Optional name for a specific chat. Pass the .md file to continue an existing chat", nargs='?', default=None)
|
|
187
|
+
|
|
188
|
+
def template_parser(subparsers):
|
|
189
|
+
template_parser = subparsers.add_parser("template", help="Output ara template")
|
|
190
|
+
template_parser.add_argument("classifier", help="Classifier for ara artefact type")
|
|
191
|
+
|
|
192
|
+
# TODO hack for ara-list command for listing python files
|
|
193
|
+
def crawl_directory(start_dir):
|
|
194
|
+
python_files = []
|
|
195
|
+
for root, dirs, files in os.walk(start_dir):
|
|
196
|
+
for file in files:
|
|
197
|
+
if file.endswith(".py"):
|
|
198
|
+
python_files.append(os.path.join(root, file))
|
|
199
|
+
return python_files
|
|
200
|
+
|
|
201
|
+
def format_output(files):
|
|
202
|
+
formatted_output = "Source files\n"
|
|
203
|
+
for file in files:
|
|
204
|
+
formatted_output += f" - [ ] {file}\n"
|
|
205
|
+
return formatted_output
|
|
206
|
+
|
|
207
|
+
def save_to_file(output, filename):
|
|
208
|
+
with open(filename, "w") as f:
|
|
209
|
+
f.write(output)
|
|
210
|
+
|
|
211
|
+
def list():
|
|
212
|
+
if len(sys.argv) != 3:
|
|
213
|
+
print("Usage: python script.py <start_directory> <output_filename>")
|
|
214
|
+
sys.exit(1)
|
|
215
|
+
|
|
216
|
+
start_dir = sys.argv[1]
|
|
217
|
+
output_filename = sys.argv[2]
|
|
218
|
+
|
|
219
|
+
python_files = crawl_directory(start_dir)
|
|
220
|
+
output = format_output(python_files)
|
|
221
|
+
save_to_file(output, output_filename)
|
|
222
|
+
print(f"File list saved to {output_filename}")
|
|
223
|
+
|
|
224
|
+
def cli():
|
|
225
|
+
parser = argparse.ArgumentParser(description="Ara tools for creating files and directories.")
|
|
226
|
+
# Add version argument
|
|
227
|
+
parser.add_argument('-v', '--version', action='version', version=f'%(prog)s {__version__}')
|
|
228
|
+
|
|
229
|
+
subparsers = parser.add_subparsers(dest="action", help="Action to perform")
|
|
230
|
+
|
|
231
|
+
create_parser(subparsers)
|
|
232
|
+
delete_parser(subparsers)
|
|
233
|
+
rename_parser(subparsers)
|
|
234
|
+
list_parser(subparsers)
|
|
235
|
+
prompt_parser(subparsers)
|
|
236
|
+
vector_parser(subparsers)
|
|
237
|
+
chat_parser(subparsers)
|
|
238
|
+
template_parser(subparsers)
|
|
239
|
+
|
|
240
|
+
action_mapping = {
|
|
241
|
+
"create": create_action,
|
|
242
|
+
"delete": delete_action,
|
|
243
|
+
"rename": rename_action,
|
|
244
|
+
"list": list_action,
|
|
245
|
+
"prompt": prompt_action,
|
|
246
|
+
"vector": vector_action,
|
|
247
|
+
"chat": chat_action,
|
|
248
|
+
"template": template_action
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
args = parser.parse_args()
|
|
252
|
+
if hasattr(args, 'action') and args.action:
|
|
253
|
+
action = action_mapping.get(args.action, handle_invalid_action)
|
|
254
|
+
action(args)
|
|
255
|
+
else:
|
|
256
|
+
parser.print_help()
|
|
257
|
+
|
|
258
|
+
if __name__ == "__main__":
|
|
259
|
+
cli()
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from typing import List, Dict
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
# Updated Pydantic model for ARA configuration
|
|
7
|
+
class ARAconfig(BaseModel):
|
|
8
|
+
ext_code_dirs: List[Dict[str, str]] = [{"source_dir": "./src"}, {"tests_dir": "./tests"}]
|
|
9
|
+
glossary_dir: str = "./glossary"
|
|
10
|
+
doc_dir: str = "./docs"
|
|
11
|
+
local_prompt_templates_dir: str = "./ara/.araconfig/prompt-modules"
|
|
12
|
+
local_ara_templates_dir: str = "./ara/.araconfig/templates/"
|
|
13
|
+
ara_prompt_given_list_includes: List[str] = [
|
|
14
|
+
"*.businessgoal", "*.vision", "*.capability", "*.keyfeature",
|
|
15
|
+
"*.epic", "*.userstory", "*.example", "*.feature", "*.task", "*.py", "*.md"
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
# Function to ensure the necessary directories exist
|
|
19
|
+
def ensure_directory_exists(directory: str):
|
|
20
|
+
if not os.path.exists(directory):
|
|
21
|
+
os.makedirs(directory)
|
|
22
|
+
print(f"New directory created at {directory}")
|
|
23
|
+
return directory
|
|
24
|
+
|
|
25
|
+
# Function to read the JSON file and return an ARAconfig model
|
|
26
|
+
def read_data(filepath: str) -> ARAconfig:
|
|
27
|
+
if not os.path.exists(filepath):
|
|
28
|
+
# If file does not exist, create it with default values
|
|
29
|
+
default_config = ARAconfig()
|
|
30
|
+
with open(filepath, 'w') as file:
|
|
31
|
+
json.dump(default_config.dict(), file, indent=4)
|
|
32
|
+
print(f"ara-tool configuration file '{filepath}' created with default configuration. Please modify it as needed and re-run your command")
|
|
33
|
+
exit() # Exit the application
|
|
34
|
+
|
|
35
|
+
with open(filepath, 'r') as file:
|
|
36
|
+
data = json.load(file)
|
|
37
|
+
return ARAconfig(**data)
|
|
38
|
+
|
|
39
|
+
# Function to save the modified configuration back to the JSON file
|
|
40
|
+
def save_data(filepath: str, config: ARAconfig):
|
|
41
|
+
with open(filepath, 'w') as file:
|
|
42
|
+
json.dump(config.dict(), file, indent=4)
|
|
43
|
+
|
|
44
|
+
# Singleton for configuration management
|
|
45
|
+
class ConfigManager:
|
|
46
|
+
_config_instance = None
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def get_config(cls, filepath='./ara/.araconfig/ara_config.json'):
|
|
50
|
+
if cls._config_instance is None:
|
|
51
|
+
cls._config_instance = read_data(filepath)
|
|
52
|
+
return cls._config_instance
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from ara_cli.classifier import Classifier
|
|
2
|
+
import subprocess
|
|
3
|
+
|
|
4
|
+
def execute_command(command, mock_input=None):
|
|
5
|
+
# print(f"DEBUG: Executing command: {command}")
|
|
6
|
+
if mock_input:
|
|
7
|
+
# print(f"DEBUG: Mock input provided: {mock_input}")
|
|
8
|
+
process = subprocess.Popen(command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
9
|
+
stdout_data, stderr_data = process.communicate(input=mock_input.encode())
|
|
10
|
+
|
|
11
|
+
# print(f"DEBUG: Command stdout: {stdout_data.decode().strip()}")
|
|
12
|
+
# print(f"DEBUG: Command stderr: {stderr_data.decode().strip()}")
|
|
13
|
+
else:
|
|
14
|
+
# print(f"DEBUG: No Mock input provided")
|
|
15
|
+
process = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
16
|
+
|
|
17
|
+
return process
|
|
18
|
+
|
|
19
|
+
class Artefact:
|
|
20
|
+
def __init__(self, name, classifier):
|
|
21
|
+
self.name = name
|
|
22
|
+
self.classifier = classifier
|
|
23
|
+
# print(f"DEBUG: Initialized Artefact with name='{name}' and classifier='{classifier}'")
|
|
24
|
+
|
|
25
|
+
def create(self):
|
|
26
|
+
command = f"ara create {self.name} {self.classifier}"
|
|
27
|
+
# print(f"DEBUG: Creating artefact with command: {command}")
|
|
28
|
+
result = execute_command(command, mock_input="y")
|
|
29
|
+
if result.returncode != 0:
|
|
30
|
+
# print(f"DEBUG: Error encountered during artefact creation.")
|
|
31
|
+
pass
|
|
32
|
+
else:
|
|
33
|
+
# print(f"DEBUG: Artefact created successfully.")
|
|
34
|
+
pass
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
def delete(self):
|
|
38
|
+
command = f"ara delete {self.name} {self.classifier}"
|
|
39
|
+
# print(f"DEBUG: Deleting artefact with command: {command}")
|
|
40
|
+
result = execute_command(command, mock_input="y")
|
|
41
|
+
if result.returncode != 0:
|
|
42
|
+
# print(f"DEBUG: Error encountered during artefact deletion.")
|
|
43
|
+
pass
|
|
44
|
+
else:
|
|
45
|
+
# print(f"DEBUG: Artefact deleted successfully.")
|
|
46
|
+
pass
|
|
47
|
+
return result
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from ara_cli.classifier import Classifier
|
|
3
|
+
from ara_cli.file_classifier import FileClassifier
|
|
4
|
+
from ara_cli.template_manager import DirectoryNavigator
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import shutil
|
|
7
|
+
from shutil import rmtree
|
|
8
|
+
from shutil import copyfile
|
|
9
|
+
|
|
10
|
+
class ArtefactCreator:
|
|
11
|
+
|
|
12
|
+
def __init__(self, file_system=None):
|
|
13
|
+
self.file_system = file_system or os
|
|
14
|
+
|
|
15
|
+
def create_artefact(self, dir_path, template_path, classifier):
|
|
16
|
+
if not template_path:
|
|
17
|
+
raise ValueError("template_path must not be None or empty!")
|
|
18
|
+
|
|
19
|
+
if not classifier:
|
|
20
|
+
raise ValueError("classifier must not be None or empty!")
|
|
21
|
+
|
|
22
|
+
# Standard exploration artefact
|
|
23
|
+
self._copy_template_file(dir_path, template_path, f"template.{classifier}_exploration.md", f"{classifier}_exploration.md")
|
|
24
|
+
|
|
25
|
+
# Additional exploration artefact for 'feature' classifier
|
|
26
|
+
if classifier == 'feature':
|
|
27
|
+
self._copy_template_file(dir_path, template_path, "template.steps_exploration.md", "steps_exploration.md")
|
|
28
|
+
|
|
29
|
+
def _copy_template_file(self, dir_path, template_path, source_name, dest_name):
|
|
30
|
+
source = Path(template_path) / source_name
|
|
31
|
+
destination = Path(dir_path) / dest_name
|
|
32
|
+
|
|
33
|
+
if not source.exists():
|
|
34
|
+
print("[ERROR] Source file does not exist!")
|
|
35
|
+
raise FileNotFoundError(f"Source file {source} not found!")
|
|
36
|
+
|
|
37
|
+
if not destination.parent.exists():
|
|
38
|
+
print("[ERROR] Destination directory does not exist!")
|
|
39
|
+
raise NotADirectoryError(f"Destination directory {destination.parent} does not exist!")
|
|
40
|
+
|
|
41
|
+
copyfile(source, destination)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def create_file(self, file_path, template_path=None, classifier=None, filename=None):
|
|
45
|
+
if template_path and classifier:
|
|
46
|
+
template_file_path = self.file_system.path.join(template_path, f"template.{classifier}")
|
|
47
|
+
if self.file_system.path.exists(template_file_path):
|
|
48
|
+
with open(template_file_path, "r") as template_file:
|
|
49
|
+
template_content = template_file.read()
|
|
50
|
+
|
|
51
|
+
formatted_filename = filename.replace("-", " ").replace("_", " ")
|
|
52
|
+
capitalized_filename = formatted_filename.capitalize()
|
|
53
|
+
|
|
54
|
+
template_content = template_content.replace("<descriptive title>", capitalized_filename)
|
|
55
|
+
|
|
56
|
+
with open(file_path, "w") as file:
|
|
57
|
+
file.write(template_content)
|
|
58
|
+
else:
|
|
59
|
+
with open(file_path, "w") as file:
|
|
60
|
+
pass
|
|
61
|
+
else:
|
|
62
|
+
with open(file_path, "w") as file:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
def create_directory(self, dir_path):
|
|
66
|
+
self.file_system.makedirs(dir_path, exist_ok=True)
|
|
67
|
+
|
|
68
|
+
def template_exists(self, template_path, template_name):
|
|
69
|
+
if not template_path:
|
|
70
|
+
return False
|
|
71
|
+
|
|
72
|
+
full_path = self.file_system.path.join(template_path, template_name)
|
|
73
|
+
|
|
74
|
+
if not self.file_system.path.isfile(full_path):
|
|
75
|
+
print(f"Template file '{template_name}' not found at: {full_path}")
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
return True
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def run(self, filename, classifier, template_path=None):
|
|
82
|
+
# make sure this function is always called from the ara top level directory
|
|
83
|
+
navigator = DirectoryNavigator()
|
|
84
|
+
navigator.navigate_to_target()
|
|
85
|
+
|
|
86
|
+
if not Classifier.is_valid_classifier(classifier):
|
|
87
|
+
print("Invalid classifier provided. Please provide a valid classifier.")
|
|
88
|
+
return
|
|
89
|
+
|
|
90
|
+
sub_directory = Classifier.get_sub_directory(classifier)
|
|
91
|
+
self.file_system.makedirs(sub_directory, exist_ok=True)
|
|
92
|
+
|
|
93
|
+
file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
|
|
94
|
+
dir_path = self.file_system.path.join(sub_directory, f"{filename}.data")
|
|
95
|
+
|
|
96
|
+
if self.file_system.path.exists(file_path) or self.file_system.path.exists(dir_path):
|
|
97
|
+
user_choice = input("File or directory already exists. Do you want to overwrite the existing file and directory? (Y/N): ")
|
|
98
|
+
|
|
99
|
+
if user_choice.lower() != "y":
|
|
100
|
+
print("No changes were made to the existing file and directory.")
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
template_name = f"template.{classifier}"
|
|
104
|
+
if template_path and not self.template_exists(template_path, template_name):
|
|
105
|
+
print(f"Template file '{template_name}' not found in the specified template path.")
|
|
106
|
+
return
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
self.create_file(file_path, template_path, classifier, filename)
|
|
111
|
+
self.create_directory(dir_path)
|
|
112
|
+
self.create_artefact(dir_path, template_path, classifier)
|
|
113
|
+
|
|
114
|
+
print(f"Created file: {file_path}")
|
|
115
|
+
print(f"Created directory: {dir_path}")
|
|
116
|
+
print(f"Created artefact exploration: {dir_path}/{classifier}_exploration.md")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# artefact_deleter.py
|
|
2
|
+
import os
|
|
3
|
+
import shutil
|
|
4
|
+
from ara_cli.template_manager import DirectoryNavigator
|
|
5
|
+
from ara_cli.classifier import Classifier
|
|
6
|
+
from ara_cli.artefact_link_updater import ArtefactLinkUpdater
|
|
7
|
+
|
|
8
|
+
class ArtefactDeleter:
|
|
9
|
+
def __init__(self, file_system=None):
|
|
10
|
+
self.file_system = file_system or os
|
|
11
|
+
self.link_updater = ArtefactLinkUpdater()
|
|
12
|
+
|
|
13
|
+
def delete(self, filename, classifier):
|
|
14
|
+
navigator = DirectoryNavigator()
|
|
15
|
+
navigator.navigate_to_target()
|
|
16
|
+
|
|
17
|
+
if not Classifier.is_valid_classifier(classifier):
|
|
18
|
+
print("Invalid classifier provided. Please provide a valid classifier.")
|
|
19
|
+
return
|
|
20
|
+
|
|
21
|
+
sub_directory = Classifier.get_sub_directory(classifier)
|
|
22
|
+
file_path = self.file_system.path.join(sub_directory, f"{filename}.{classifier}")
|
|
23
|
+
dir_path = self.file_system.path.join(sub_directory, f"{filename}.data")
|
|
24
|
+
|
|
25
|
+
if not self.file_system.path.exists(file_path) or not self.file_system.path.exists(dir_path):
|
|
26
|
+
print("File or directory not found.")
|
|
27
|
+
return
|
|
28
|
+
|
|
29
|
+
user_choice = input("Are you sure you want to delete the file and directory? (Y/N): ")
|
|
30
|
+
|
|
31
|
+
if user_choice.lower() != "y":
|
|
32
|
+
print("No changes were made.")
|
|
33
|
+
return
|
|
34
|
+
|
|
35
|
+
# Remove references to this artefact in other artefacts before deletion
|
|
36
|
+
self.link_updater.remove_links_in_related_artefacts(filename)
|
|
37
|
+
|
|
38
|
+
self.file_system.remove(file_path)
|
|
39
|
+
shutil.rmtree(dir_path)
|
|
40
|
+
|
|
41
|
+
print(f"Deleted file: {file_path}")
|
|
42
|
+
print(f"Deleted directory: {dir_path}")
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# artefact_link_updater.py
|
|
2
|
+
import os
|
|
3
|
+
import re
|
|
4
|
+
from ara_cli.classifier import Classifier
|
|
5
|
+
|
|
6
|
+
class ArtefactLinkUpdater:
|
|
7
|
+
|
|
8
|
+
def __init__(self, file_system=None):
|
|
9
|
+
self.file_system = file_system or os
|
|
10
|
+
|
|
11
|
+
def update_links_in_related_artefacts(self, old_name, new_name, dir_path='.'):
|
|
12
|
+
new_name_formatted = new_name.replace('_', ' ').capitalize()
|
|
13
|
+
old_name_pattern = re.compile(f"\\b{old_name.replace(' ', '[ _]').replace('_', '[ _]')}\\b", re.IGNORECASE)
|
|
14
|
+
|
|
15
|
+
patterns = {
|
|
16
|
+
re.compile(f"^(\\s*)Contributes to[ ]+([A-Za-z ]+)?{old_name_pattern.pattern}", re.IGNORECASE | re.MULTILINE): r"\1Contributes to \2" + new_name_formatted,
|
|
17
|
+
re.compile(f"^(\\s*)Illustrates[ ]+([A-Za-z ]+)?{old_name_pattern.pattern}", re.IGNORECASE | re.MULTILINE): r"\1Illustrates \2" + new_name_formatted
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Iterate over all items in the directory
|
|
21
|
+
for item in self.file_system.listdir(dir_path):
|
|
22
|
+
item_path = self.file_system.path.join(dir_path, item)
|
|
23
|
+
extension = os.path.splitext(item)[-1][1:]
|
|
24
|
+
|
|
25
|
+
# Check if it's a directory, then recurse
|
|
26
|
+
if self.file_system.path.isdir(item_path):
|
|
27
|
+
self.update_links_in_related_artefacts(old_name, new_name, item_path)
|
|
28
|
+
|
|
29
|
+
# Check if it's a file and not a directory
|
|
30
|
+
elif self.file_system.path.isfile(item_path) and Classifier.is_valid_classifier(extension):
|
|
31
|
+
# Read the content of the file
|
|
32
|
+
with open(item_path, 'r') as file:
|
|
33
|
+
content = file.read()
|
|
34
|
+
|
|
35
|
+
# Replace all occurrences of the old name with the new name using regular expressions
|
|
36
|
+
for pattern, replacement in patterns.items():
|
|
37
|
+
content = pattern.sub(replacement, content)
|
|
38
|
+
|
|
39
|
+
# Write the updated content back to the file
|
|
40
|
+
with open(item_path, 'w') as file:
|
|
41
|
+
file.write(content)
|
|
42
|
+
|
|
43
|
+
def remove_links_in_related_artefacts(self, artefact_name, dir_path="."):
|
|
44
|
+
artefact_name_pattern = re.compile(rf"\b{re.escape(artefact_name)}\b", re.IGNORECASE)
|
|
45
|
+
|
|
46
|
+
# Pattern for removing the artefact name from 'Contributes to' lines
|
|
47
|
+
contribute_pattern = re.compile(rf"^(Contributes to).*{artefact_name_pattern.pattern}.*$", re.IGNORECASE | re.MULTILINE)
|
|
48
|
+
|
|
49
|
+
# Pattern for removing the artefact name from 'Illustrates' lines (no colon)
|
|
50
|
+
illustrates_pattern = re.compile(rf"^(Illustrates).*{artefact_name_pattern.pattern}.*$", re.IGNORECASE | re.MULTILINE)
|
|
51
|
+
|
|
52
|
+
# Iterate over all items in the directory
|
|
53
|
+
for item in self.file_system.listdir(dir_path):
|
|
54
|
+
item_path = self.file_system.path.join(dir_path, item)
|
|
55
|
+
extension = os.path.splitext(item)[-1][1:]
|
|
56
|
+
|
|
57
|
+
# Check if it's a directory, then recurse
|
|
58
|
+
if self.file_system.path.isdir(item_path):
|
|
59
|
+
self.remove_links_in_related_artefacts(artefact_name, item_path)
|
|
60
|
+
|
|
61
|
+
# Check if it's a file and not a directory, and if extension is a valid artefact classifier
|
|
62
|
+
elif self.file_system.path.isfile(item_path) and Classifier.is_valid_classifier(extension):
|
|
63
|
+
with open(item_path, 'r') as file:
|
|
64
|
+
content = file.read()
|
|
65
|
+
|
|
66
|
+
# Remove the artefact name from 'Contributes to' and 'Illustrates' lines
|
|
67
|
+
content = contribute_pattern.sub("Contributes to", content)
|
|
68
|
+
content = illustrates_pattern.sub("Illustrates", content)
|
|
69
|
+
|
|
70
|
+
with open(item_path, 'w') as file:
|
|
71
|
+
file.write(content)
|
|
72
|
+
|