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

Preparing for 0.8 version #243

Merged
merged 31 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
83a39b5
Testing
javizqh Jan 7, 2025
a62714b
Working docker zip
javizqh Jan 7, 2025
ab03482
Cleanup
javizqh Jan 7, 2025
55deae9
Remove hardcoded files
javizqh Jan 7, 2025
83d32b8
Fix bug and remove hardcoded templates
javizqh Jan 7, 2025
87fc3bc
Removing hardcoded json translator
javizqh Jan 7, 2025
bfc5eb7
Moving app creation to the frontend
javizqh Jan 7, 2025
a38fb99
Linter
javizqh Jan 7, 2025
0b7acf3
Remove useless function
javizqh Jan 7, 2025
068edc6
Remove template from file
javizqh Jan 7, 2025
7a4564f
Fix file creation bug
javizqh Jan 7, 2025
595de19
Fix bug when creating folder
javizqh Jan 7, 2025
f5e0d94
Separate delete into 2
javizqh Jan 8, 2025
6d27fec
Fix and separate rename file and folder
javizqh Jan 8, 2025
5ed660d
Fix autosave and save on rename
javizqh Jan 8, 2025
fce79a4
Rename save project config
javizqh Jan 8, 2025
6605b1f
Fix saving proj config
javizqh Jan 8, 2025
9488df6
Save bt before executing
javizqh Jan 8, 2025
956b494
Linter
javizqh Jan 8, 2025
cc290ac
Remove zips from upload code
javizqh Jan 9, 2025
178b189
Remove download_data
javizqh Jan 9, 2025
9626c09
Download zip in frontend
javizqh Jan 9, 2025
67f6792
Change get methods to get and move all API calls to TreeWrapper.ts
javizqh Jan 9, 2025
ed75ef3
Remove duplicate header
javizqh Jan 9, 2025
0644335
Escape \ correctly
javizqh Jan 9, 2025
20f11ea
Fix state check in reset App
javizqh Jan 9, 2025
2246998
Change save diagram method
javizqh Jan 9, 2025
8432155
New add subtree modal
javizqh Jan 9, 2025
f8eb564
Fix update problems
javizqh Jan 9, 2025
f10b7e6
Fix lose saved link in bt
javizqh Jan 9, 2025
cc04fb4
Linter
javizqh Jan 9, 2025
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
182 changes: 3 additions & 179 deletions backend/tree_api/app_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,194 +10,18 @@
##############################################################################


# Zip a directory
def zipdir(path, ziph):

for root, dirs, files in os.walk(path):
for file in files:
ziph.write(
os.path.join(root, file),
os.path.relpath(os.path.join(root, file), path),
)


# Rename all the necessary files in the template
def rename_template_files(root_path, original_str, replacement_str):

for dirpath, dirnames, filenames in os.walk(root_path, topdown=False):

# Rename directories
for dirname in dirnames:
if original_str in dirname:
src_dir = os.path.join(dirpath, dirname)
dst_dir = os.path.join(
dirpath, dirname.replace(original_str, replacement_str)
)
os.rename(src_dir, dst_dir)

# Rename files
for filename in filenames:
if original_str in filename:
src_file = os.path.join(dirpath, filename)
dst_file = os.path.join(
dirpath, filename.replace(original_str, replacement_str)
)
os.rename(src_file, dst_file)


# Replace a str in a file for another
def replace_contents_in_file(file_path, original_str, replacement_str):

with open(file_path, "r") as file:
file_data = file.read()

new_data = file_data.replace(original_str, replacement_str)

with open(file_path, "w") as file:
file.write(new_data)


def get_actions_paths(dir_to_scan):

files_to_scan = []
for root, _, filenames in os.walk(dir_to_scan):
for filename in filenames:
if filename.endswith(".py"):
files_to_scan.append(os.path.join(root, filename))

return files_to_scan


# Collect unique imports from files
def get_unique_imports(file_paths):
def get_unique_imports(actions):

unique_imports = set()

for file_path in file_paths:
if not os.path.exists(file_path):
print(
f"Warning: File {file_path} does not exist. Skipping import collection for this file."
)
continue

with open(file_path, "r") as file:
lines = file.readlines()
for action in actions:
lines = action["content"].splitlines()

for line in lines:
# Using regex to find lines that don't start with '#' and have 'import ...' or 'from ... import ...'
match = re.search(r"^(?!#.*)(?:import|from)\s+(\w+)", line)
if match:
unique_imports.add(match.group(1))

f = open("/tmp/imports.txt", "w")
f.write(f"Action paths: {unique_imports}.")
f.close()

return list(unique_imports)


def update_package_xml(package_xml_path, unique_imports):
# Mapping from Python import names to ROS package names
special_imports = {
"cv2": "python3-opencv",
# Add more mappings here as needed
}

with open(package_xml_path, "r") as file:
content = file.read()

# Finding the position of the last </exec_depend> tag
last_exec_depend_index = content.rfind("</exec_depend>") + len("</exec_depend>")

# Replacing special import names and generating new <exec_depend> entries
new_exec_depends = "\n".join(
[
f" <exec_depend>{special_imports.get(imp, imp)}</exec_depend>"
for imp in unique_imports
]
)

# Inserting the new dependencies after the last </exec_depend>
updated_content = (
content[:last_exec_depend_index]
+ "\n"
+ new_exec_depends
+ content[last_exec_depend_index:]
)

# Writing the updated content back to package.xml
with open(package_xml_path, "w") as file:
file.write(updated_content)


# Setup the package with the user data
def setup_package(temp_path, action_path, user_data):

app_name = user_data["app_name"]
template_str = "ros_template"

# 1. Rename directories and files recursively
rename_template_files(temp_path, template_str, app_name)

# 2. Replace the original_str with app_name in the content of relevant files
files_to_edit = ["package.xml", "setup.py", "setup.cfg", app_name + "/execute.py"]
for file_name in files_to_edit:
file_path = os.path.join(temp_path, file_name)
if os.path.exists(file_path):
replace_contents_in_file(file_path, template_str, app_name)
else:
print(
f"Warning: {file_name} not found in {temp_path}. Skipping content replacement for this file."
)

# 3. Get a list of unique imports from the user-defined actions
action_paths = get_actions_paths(action_path)
imports = get_unique_imports(action_paths)

# 4. Update the template package xml so the dependencies can be installed with rosdep
package_xml_path = os.path.join(temp_path, "package.xml")
update_package_xml(package_xml_path, imports)


##############################################################################
# Main section
##############################################################################


def generate(app_tree, app_name, template_path, action_path, tree_gardener_src):

app_path = "/tmp/" + app_name
executor_path = app_path + "/" + app_name
tree_gardener_dst = app_path + "/tree_gardener"

# Ensure the files exist
if not os.path.exists(app_tree):
raise FileNotFoundError(f"Tree path '{app_tree}' does not exist!")

# 1. Copy the template to a temporary directory
if os.path.exists(executor_path):
shutil.rmtree(executor_path) # Delete if it already exists
shutil.copytree(template_path, executor_path)
print(f"Template copied to {executor_path}")

# 2. Copy the tree to the template directory
tree_location = executor_path + "/resource/app_tree.xml"
shutil.copy(app_tree, tree_location)

# 3. Edit some files in the template
user_data = {"app_name": app_name}
setup_package(executor_path, action_path, user_data)

# 4. Copy the tree_gardener package to the app
if os.path.exists(tree_gardener_dst):
shutil.rmtree(tree_gardener_dst) # Delete if it already exists
shutil.copytree(tree_gardener_src, tree_gardener_dst)
print(f"Tree gardener copied to {tree_gardener_dst}")

# 3. Generate a zip file in the destination folder with a name specified by the user
dest_path = app_path + ".zip"
with zipfile.ZipFile(dest_path, "w") as zipf:
zipdir(app_path, zipf)
print(f"Directory compressed to {dest_path}")

return dest_path
11 changes: 3 additions & 8 deletions backend/tree_api/json_translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ def get_start_node_id(node_models, link_models):
return start_node_id


def translate(content, tree_path, raw_order):
def translate_raw(content, raw_order):

# Parse the JSON data
try:
Expand Down Expand Up @@ -189,16 +189,11 @@ def translate(content, tree_path, raw_order):
order,
)
except Exception as e:
tree_name = os.path.splitext(os.path.basename(tree_path))[0]
raise RuntimeError(f"Failed to translate tree '{tree_name}': {e}")
raise RuntimeError(f"Failed to translate tree: {e}")

# Save the xml in the specified route
xml_string = prettify_xml(root)
print(xml_string)
print(tree_path)
f = open(tree_path, "w")
f.write(xml_string)
f.close()
return xml_string


def translate_tree_structure(content, raw_order):
Expand Down
34 changes: 6 additions & 28 deletions backend/tree_api/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,10 @@
from django.conf import settings


def create_action_from_template(file_path, filename, template):
def get_action_template(filename, template, template_path):

templates_folder_path = os.path.join(settings.BASE_DIR, "templates")
template_path = os.path.join(templates_folder_path, template)

replacements = {"ACTION": filename[:-3]}

if template == "empty":
with open(file_path, "w") as f:
f.write("") # Empty content
return True
elif template == "action":
with open(file_path, "w") as f:
with open(template_path, "r") as temp:
for line in temp:
for src, target in replacements.items():
line = line.replace(src, target)
f.write(line)
return True
elif template == "io":
with open(file_path, "w") as f:
with open(template_path, "r") as temp:
for line in temp:
for src, target in replacements.items():
line = line.replace(src, target)
f.write(line)
return True
else:
return False
with open(template_path, "r") as temp:
file_data = temp.read()
new_data = file_data.replace("ACTION", filename)
return new_data
return ""
Loading
Loading