Macos bundler .pkg

Adding .pkg bundling for mac to avoid permission problems

frdel committed Oct 18, 2024 at 11:05 UTC a300abc67a998ebfb7bf56c78cfc690c0e7c7fa6
5 files changed +171 -71
.gitignore
+3 -1
@@ -10,7 +10,9 @@
10 .venv/
11
12 # ignore all folders under /bundle
13 -/bundle/*/
13 +bundle/*/
14 +# except some
15 +!bundle/mac_pkg_scripts
16
17 # Ignore all contents of the directory "work_dir"
18 work_dir/*
bundle/bundle.py
+40 -4
@@ -7,7 +7,8 @@ from pathlib import Path
7 import pathspec
8 import importlib
9 import importlib.metadata as metadata
10 -import py7zr # New import for 7z compression
10 +import py7zr
11 +import zipfile
12
13 def get_package_data_folder(package_name):
14 """Return the package path if it contains data files."""
@@ -77,6 +78,38 @@ def cleanup_directories(bundle_name, build_dir, dist_dir, keep_dist=False):
78 if os.path.exists(spec_file):
79 os.remove(spec_file)
80
81 +def compress_internal_folder(dist_dir, exe_name):
82 + """Compress the _internal folder using zipfile."""
83 + try:
84 + internal_path = Path(dist_dir) / exe_name / "_internal"
85 + archive_path = internal_path.parent / "_internal.zip"
86 +
87 + if not internal_path.exists():
88 + print("Warning: _internal folder not found")
89 + return False
90 +
91 + # Remove existing archive if it exists
92 + if archive_path.exists():
93 + archive_path.unlink()
94 +
95 + print(f"Compressing _internal folder to: {archive_path}")
96 +
97 + # Create the zip archive
98 + with zipfile.ZipFile(archive_path, 'w', zipfile.ZIP_STORED) as archive:
99 + for root, dirs, files in os.walk(internal_path):
100 + for file in files:
101 + file_path = Path(root) / file
102 + archive.write(file_path, arcname=file_path.relative_to(internal_path.parent))
103 +
104 + # Remove the original _internal folder
105 + shutil.rmtree(internal_path)
106 + print("_internal folder compressed and removed successfully")
107 + return True
108 +
109 + except Exception as e:
110 + print(f"Error during _internal compression: {e}")
111 + return False
112 +
113 def compress_dist_folder(dist_dir, exe_name):
114 """Compress the dist folder using py7zr library."""
115 try:
@@ -91,8 +124,8 @@ def compress_dist_folder(dist_dir, exe_name):
124 print(f"Compressing dist folder to: {archive_path}")
125
126 # Create the 7z archive with maximum compression
94 - with py7zr.SevenZipFile(archive_path, 'w', filters=[{'id': py7zr.FILTER_LZMA2, 'preset': 9}]) as archive:
95 - archive.writeall(files_path, arcname=dist_dir.name)
127 + with py7zr.SevenZipFile(archive_path, 'w', filters=[{'id': py7zr.FILTER_LZMA2, 'preset': 2}]) as archive:
128 + archive.writeall(files_path, arcname=files_path.name)
129
130 print("Compression completed successfully")
131 return str(archive_path)
@@ -172,6 +205,9 @@ def build_executable(script_path, exe_name=None, compress=False):
205 print(f"Executable created at: '{dist_dir}/{exe_name}'")
206 print(f"Project files copied to: '{project_files_dir}'")
207
208 + # Compress the _internal folder first
209 + # compress_internal_folder(dist_dir, exe_name)
210 +
211 # Compress the dist folder if requested
212 if compress:
213 archive_path = compress_dist_folder(dist_dir, exe_name)
@@ -187,4 +223,4 @@ def build_executable(script_path, exe_name=None, compress=False):
223 print(f"Error: {e}")
224
225 if __name__ == "__main__":
190 - build_executable("../run_bundle.py", "agent-zero", compress=True)
\ No newline at end of file
226 + build_executable("../run_bundle.py", "agent-zero", compress=False)
\ No newline at end of file
bundle/mac_pkg_scripts/postinstall new
+36
@@ -0,0 +1,36 @@
1 +#!/bin/bash
2 +
3 +# Prompt the user to select a folder using an AppleScript dialog
4 +TARGET_FOLDER=$(osascript <<EOT
5 + tell application "System Events"
6 + activate
7 + set chosenFolder to choose folder with prompt "Please select a folder for the installation:"
8 + return POSIX path of chosenFolder
9 + end tell
10 +EOT
11 +)
12 +
13 +# Check if the user selected a folder
14 +if [ -n "$TARGET_FOLDER" ]; then
15 + echo "Installing files to $TARGET_FOLDER"
16 +
17 + # Move the installed files to the selected folder
18 + mv /tmp/agent-zero/* "$TARGET_FOLDER"
19 +
20 + # Check if the move operation was successful
21 + if [ $? -eq 0 ]; then
22 + echo "Files successfully moved to $TARGET_FOLDER"
23 +
24 + # Remove the /tmp/agent-zero folder
25 + rm -rf /tmp/agent-zero
26 + echo "/tmp/agent-zero folder removed."
27 + else
28 + echo "Error moving files. Exiting."
29 + exit 1
30 + fi
31 +else
32 + echo "No folder selected. Exiting installation."
33 + exit 1
34 +fi
35 +
36 +exit 0
\ No newline at end of file
bundle/macos_bundle.sh
+26 -14
@@ -38,8 +38,8 @@ if [ -d "agent-zero" ]; then
38 fi
39
40 # 4. Clone the repository (development branch)
41 -echo "Cloning the repository (testing branch)..."
42 -git clone --branch testing https://github.com/frdel/agent-zero agent-zero
41 +echo "Cloning the repository (development branch)..."
42 +git clone --branch development https://github.com/frdel/agent-zero agent-zero
43 if [ $? -ne 0 ]; then
44 echo "Error cloning the repository."
45 exit 1
@@ -67,18 +67,30 @@ if [ $? -ne 0 ]; then
67 exit 1
68 fi
69
70 -# 9. Move the generated 7z file to the script directory and remove agent-zero folder
71 -BUNDLE_FILE="bundle/dist/agent-zero.7z"
72 -if [ -f "$BUNDLE_FILE" ]; then
73 - SCRIPT_DIR=$(dirname "$0")
74 - echo "Moving $BUNDLE_FILE to $SCRIPT_DIR..."
75 - mv "$BUNDLE_FILE" "$SCRIPT_DIR"
76 - if [ $? -ne 0 ]; then
77 - echo "Error moving $BUNDLE_FILE to $SCRIPT_DIR."
78 - exit 1
79 - fi
80 -else
81 - echo "Error: $BUNDLE_FILE not found."
70 +# # 9. Move the generated 7z file to the script directory and remove agent-zero folder
71 +# BUNDLE_FILE="bundle/dist/agent-zero.7z"
72 +# if [ -f "$BUNDLE_FILE" ]; then
73 +# SCRIPT_DIR=$(dirname "$0")
74 +# echo "Moving $BUNDLE_FILE to $SCRIPT_DIR..."
75 +# mv "$BUNDLE_FILE" "$SCRIPT_DIR"
76 +# if [ $? -ne 0 ]; then
77 +# echo "Error moving $BUNDLE_FILE to $SCRIPT_DIR."
78 +# exit 1
79 +# fi
80 +# else
81 +# echo "Error: $BUNDLE_FILE not found."
82 +# exit 1
83 +# fi
84 +
85 +# 9. Create macOS package
86 +echo "Creating macOS package..."
87 +pkgbuild --root ./dist/agent-zero \
88 + --identifier frdel.agent-zero \
89 + --install-location /tmp/agent-zero \
90 + --scripts ./mac_pkg_scripts \
91 + agent-zero-preinstalled-mac-m1.pkg
92 +if [ $? -ne 0 ]; then
93 + echo "Error creating macOS package."
94 exit 1
95 fi
96
run_bundle.py
+66 -52
@@ -1,64 +1,78 @@
1 -print("\nImporting dependencies, this may take a while...\n")
1 +def post_install():
2 + # if "_internal.zip" exists, unzip and remove
3 + import os
4 + if os.path.exists("_internal.zip"):
5 + import zipfile
6 + print("\nDecompressing internal binaries...\n")
7 + with zipfile.ZipFile("_internal.zip", 'r') as zip_ref:
8 + zip_ref.extractall("_internal")
9 + os.remove("_internal.zip")
10 +
11 +def run_bundle():
12 + print("\nImporting dependencies, this may take a while...\n")
13 +
14 + # dependencies to bundle
15 + import ansio
16 + import bs4
17 + import docker
18 + import duckduckgo_search
19 + import faiss
20 + from flask import Flask
21 + import flask_basicauth
22 + import inputimeout
23 + import langchain.embeddings
24 + import langchain_anthropic
25 + import langchain_community
26 + import langchain_google_genai
27 + import langchain_groq
28 + import langchain_huggingface
29 + import langchain_mistralai
30 + import langchain_ollama
31 + import langchain_openai
32 + import lxml_html_clean
33 + import emoji
34 + from emoji import unicode_codes
35 + import markdown
36 + import newspaper
37 + import paramiko
38 + import pypdf
39 + import dotenv
40 + import sentence_transformers
41 + from tiktoken import model, registry
42 + from tiktoken_ext import openai_public
43 + import unstructured
44 + import unstructured_client
45 + import webcolors
46
47
4 -# dependencies to bundle
5 -import ansio
6 -import bs4
7 -import docker
8 -import duckduckgo_search
9 -import faiss
10 -from flask import Flask
11 -import flask_basicauth
12 -import inputimeout
13 -import langchain.embeddings
14 -import langchain_anthropic
15 -import langchain_community
16 -import langchain_google_genai
17 -import langchain_groq
18 -import langchain_huggingface
19 -import langchain_mistralai
20 -import langchain_ollama
21 -import langchain_openai
22 -import lxml_html_clean
23 -import emoji
24 -from emoji import unicode_codes
25 -import markdown
26 -import newspaper
27 -import paramiko
28 -import pypdf
29 -import dotenv
30 -import sentence_transformers
31 -from tiktoken import model, registry
32 -from tiktoken_ext import openai_public
33 -import unstructured
34 -import unstructured_client
35 -import webcolors
48
49 + # but do not bundle project files, these are to be imported at runtime
50
51
39 -# but do not bundle project files, these are to be imported at runtime
52
53 + import sys
54 + import os
55 + import importlib.util
56
57 + # Add the project_files directory to the Python path
58 + project_files_dir = os.path.join(os.path.dirname(sys.executable), 'agent-zero-files')
59 + sys.path.insert(0, project_files_dir)
60
43 -import sys
44 -import os
45 -import importlib.util
61 + # Dynamically load the 'run_ui' module
62 + module_name = "run_ui"
63 + module_path = os.path.join(project_files_dir, f"{module_name}.py")
64
47 -# Add the project_files directory to the Python path
48 -project_files_dir = os.path.join(os.path.dirname(sys.executable), 'agent-zero-files')
49 -sys.path.insert(0, project_files_dir)
65 + # Load the module at runtime
66 + spec = importlib.util.spec_from_file_location(module_name, module_path)
67 + if spec and spec.loader:
68 + run_ui = importlib.util.module_from_spec(spec)
69 + spec.loader.exec_module(run_ui)
70
51 -# Dynamically load the 'run_ui' module
52 -module_name = "run_ui"
53 -module_path = os.path.join(project_files_dir, f"{module_name}.py")
71 + # Now you can call the function in the dynamically imported module
72 + run_ui.run() # Call the 'run' function from run_ui
73 + else:
74 + raise Exception(f"Could not load {module_name} from {module_path}")
75
55 -# Load the module at runtime
56 -spec = importlib.util.spec_from_file_location(module_name, module_path)
57 -if spec and spec.loader:
58 - run_ui = importlib.util.module_from_spec(spec)
59 - spec.loader.exec_module(run_ui)
76
61 - # Now you can call the function in the dynamically imported module
62 - run_ui.run() # Call the 'run' function from run_ui
63 -else:
64 - raise Exception(f"Could not load {module_name} from {module_path}")
\ No newline at end of file
77 +# post_install()
78 +run_bundle()
\ No newline at end of file