Ability to checkout git repos, custom ports, and setup for pip

This commit is contained in:
Brett Williams
2025-03-12 00:20:25 -05:00
parent 94e0ecda83
commit b0d3660881
6 changed files with 181 additions and 85 deletions

View File

@@ -1,11 +1,11 @@
# Cross-Py-Build # Cross-Py-Builder
Cross-Py-Build is a simple remote build tool for compiling Python projects with PyInstaller on different platforms on a local network. Cross-Py-Builder is a simple remote build tool for compiling Python projects with PyInstaller on different platforms on a local network.
## System Requirements ## System Requirements
- **Ubuntu/Debian & macOS:** 2GB+ RAM - **Ubuntu/Debian & macOS:** 2GB+ RAM
- **Windows:** 4GB+ RAM - **Windows:** 4GB+ RAM
- **Python 3** installed - **Python 3.10 or later** installed
- **Local Network** for build agents - **Local Network** for build agents
--- ---
@@ -14,7 +14,7 @@ Cross-Py-Build is a simple remote build tool for compiling Python projects with
```sh ```sh
./agent_manager.py --build /path/to/repo -cpu x64 -os windows ./cross-py-builder.py --build /path/to/repo -cpu x64 -os windows
options: options:
-h, --help show this help message and exit -h, --help show this help message and exit
@@ -28,7 +28,7 @@ options:
--restart RESTART Hostname to restart --restart RESTART Hostname to restart
--restart-all Restart all agents --restart-all Restart all agents
--shutdown SHUTDOWN Hostname to shutdown --shutdown SHUTDOWN Hostname to shutdown
--shutdown-all Restart all agents --shutdown-all Shutdown all agents
``` ```
--- ---
@@ -50,29 +50,23 @@ This guide provides steps to set up a worker VM on **Ubuntu/Debian, macOS, or Wi
```sh ```sh
xcode-select --install # Install xcode tools xcode-select --install # Install xcode tools
``` ```
- Install Python 3.x from [python.org](https://www.python.org/downloads/) 3. **Install Python** >=3.10 from [python.org](https://www.python.org/downloads/) (Windows and macOS - macOS)
- **Windows:** 4. **Set up a virtual environment:**
- Install Python 3.x from [python.org](https://www.python.org/downloads/)
3. **Set up a virtual environment:**
- **Ubuntu/Debian/macOS:** - **Ubuntu/Debian/macOS:**
```sh ```sh
python3 -m venv venv python3 -m venv venv
source venv/bin/activate source venv/bin/activate
``` ```
- **Windows:** - **Windows:**
```sh ```sh
python3 -m venv venv python3 -m venv venv
source venv\Scripts\activate venv\Scripts\activate
``` ```
4. **Copy project files** and install dependencies: 5. **Copy project files** and install dependencies:
```sh ```sh
pip install -r requirements.txt pip install -r requirements.txt
``` ```
6. **Start Build Agent**:
5. **Start Build Agent**:
- **Ubuntu/Debian/macOS:** - **Ubuntu/Debian/macOS:**
```sh ```sh
python3 build_agent.py python3 build_agent.py

View File

View File

@@ -18,7 +18,8 @@ import platform
from zeroconf_server import ZeroconfServer from zeroconf_server import ZeroconfServer
APP_NAME = "cross-py-builder" APP_NAME = "cross-py-builder"
build_agent_version = "0.1.33" build_agent_version = "0.1.34"
app_port = 9001
app = Flask(__name__) app = Flask(__name__)
launch_time = datetime.datetime.now() launch_time = datetime.datetime.now()
@@ -148,12 +149,39 @@ def status():
"python": platform.python_version(), "python": platform.python_version(),
"hostname": hostname, "hostname": hostname,
"ip": ZeroconfServer.get_local_ip(), "ip": ZeroconfServer.get_local_ip(),
"port": app_port,
"job_id": system_status['running_job'], "job_id": system_status['running_job'],
"cache_size": format_size(get_directory_size(TMP_DIR)), "cache_size": format_size(get_directory_size(TMP_DIR)),
"uptime": str(datetime.datetime.now() - launch_time) "uptime": str(datetime.datetime.now() - launch_time)
}) })
def generate_job_id():
return str(uuid.uuid4()).split('-')[-1]
@app.route("/checkout_git", methods=['POST'])
def checkout_project():
start_time = datetime.datetime.now()
repo_url = request.json.get('repo_url')
if not repo_url:
return jsonify({'error': 'Repository URL is required'}), 400
print(f"\n========== Checking Out Git Project ==========")
job_id = generate_job_id()
repo_dir = os.path.join(TMP_DIR, job_id)
try:
system_status['status'] = "cloning_repo"
subprocess.check_call(['git', 'clone', repo_url, repo_dir])
system_status['status'] = "ready"
except subprocess.CalledProcessError as e:
print(f"Error cloning repo: {e}")
system_status['status'] = "ready"
return jsonify({'error': 'Failed to clone repository'}), 500
return install_and_build(repo_dir, job_id, start_time)
@app.route('/upload', methods=['POST']) @app.route('/upload', methods=['POST'])
def upload_project(): def upload_project():
try: try:
@@ -161,8 +189,9 @@ def upload_project():
if 'file' not in request.files: if 'file' not in request.files:
return jsonify({"error": "No file uploaded"}), 400 return jsonify({"error": "No file uploaded"}), 400
system_status['status'] = "processing_files"
print(f"\n========== Processing Incoming Project ==========") print(f"\n========== Processing Incoming Project ==========")
job_id = str(uuid.uuid4()).split('-')[-1] job_id = generate_job_id()
working_dir = os.path.join(TMP_DIR, BUILD_DIR, job_id) working_dir = os.path.join(TMP_DIR, BUILD_DIR, job_id)
file = request.files['file'] file = request.files['file']
@@ -180,7 +209,8 @@ def upload_project():
return install_and_build(working_dir, job_id, start_time) return install_and_build(working_dir, job_id, start_time)
except Exception as e: except Exception as e:
print(f"Uncaught error processing job: {e}") print(f"Uncaught error processing job: {e}")
jsonify({"error": f"Uncaught error processing job: {e}"}), 500 system_status['status'] = "ready"
return jsonify({"error": f"Uncaught error processing job: {e}"}), 500
def install_and_build(project_path, job_id, start_time): def install_and_build(project_path, job_id, start_time):
@@ -196,6 +226,7 @@ def install_and_build(project_path, job_id, start_time):
# Set up virtual environment # Set up virtual environment
venv_path = os.path.join(project_path, "venv") venv_path = os.path.join(project_path, "venv")
try: try:
system_status['status'] = "creating_venv"
print(f"\n========== Configuring Virtual Environment ({venv_path}) ==========") print(f"\n========== Configuring Virtual Environment ({venv_path}) ==========")
python_exec = "python" if is_windows() else "python3" python_exec = "python" if is_windows() else "python3"
subprocess.run([python_exec, "-m", "venv", venv_path], check=True) subprocess.run([python_exec, "-m", "venv", venv_path], check=True)
@@ -212,6 +243,7 @@ def install_and_build(project_path, job_id, start_time):
# Install requirements # Install requirements
try: try:
system_status['status'] = "installing_packages"
subprocess.run([py_exec, "-m", "pip", "install", "--upgrade", "pip"], check=True) subprocess.run([py_exec, "-m", "pip", "install", "--upgrade", "pip"], check=True)
subprocess.run([py_exec, "-m", "pip", "install", "pyinstaller", "pyinstaller_versionfile", "--prefer-binary"], check=True) subprocess.run([py_exec, "-m", "pip", "install", "pyinstaller", "pyinstaller_versionfile", "--prefer-binary"], check=True)
requirements_path = os.path.join(project_path, "requirements.txt") requirements_path = os.path.join(project_path, "requirements.txt")
@@ -230,6 +262,7 @@ def install_and_build(project_path, job_id, start_time):
try: try:
for index, spec_file in enumerate(spec_files): for index, spec_file in enumerate(spec_files):
# Compile with PyInstaller # Compile with PyInstaller
system_status['status'] = "compiling"
print(f"\n========== Compiling spec file {index+1} of {len(spec_files)} - {spec_file} ==========") print(f"\n========== Compiling spec file {index+1} of {len(spec_files)} - {spec_file} ==========")
simple_name = os.path.splitext(os.path.basename(spec_file))[0] simple_name = os.path.splitext(os.path.basename(spec_file))[0]
dist_path = os.path.join(project_path, "dist") dist_path = os.path.join(project_path, "dist")
@@ -242,17 +275,26 @@ def install_and_build(project_path, job_id, start_time):
[py_exec, "-m", "PyInstaller", spec_file, "--distpath", dist_path, "--workpath", work_path], [py_exec, "-m", "PyInstaller", spec_file, "--distpath", dist_path, "--workpath", work_path],
text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
) )
last_line = None
for line in process.stdout: for line in process.stdout:
print(line, end="") # Print to console last_line = line
log_file.write(line) # Save to log file print(line, end="")
log_file.flush() # Ensure real-time writing log_file.write(line)
process.wait() # Wait for the process to complete log_file.flush()
process.wait()
if process.returncode != 0:
raise RuntimeError(
f"PyInstaller failed with exit code {process.returncode}. Last line: {str(last_line).strip()}")
print(f"\n========== Compilation of spec file {spec_file} complete ==========\n") print(f"\n========== Compilation of spec file {spec_file} complete ==========\n")
except Exception as e: except Exception as e:
print(f"Error compiling project: {e}") print(f"Error compiling project: {e}")
system_status['status'] = "ready" system_status['status'] = "ready"
system_status['running_job'] = None system_status['running_job'] = None
os.remove(project_path) try:
os.remove(project_path)
except PermissionError:
pass
return jsonify({"error": f"Error compiling project: {e}"}), 500 return jsonify({"error": f"Error compiling project: {e}"}), 500
dist_path = os.path.join(project_path, "dist") dist_path = os.path.join(project_path, "dist")
@@ -355,10 +397,10 @@ def delete_cache():
if __name__ == "__main__": if __name__ == "__main__":
print(f"===== {APP_NAME} Build Agent (v{build_agent_version}) =====") print(f"===== {APP_NAME} Build Agent (v{build_agent_version}) =====")
ZeroconfServer.configure("_crosspybuilder._tcp.local.", socket.gethostname(), 9001) ZeroconfServer.configure("_crosspybuilder._tcp.local.", socket.gethostname(), app_port)
try: try:
ZeroconfServer.start() ZeroconfServer.start()
app.run(host="0.0.0.0", port=9001, threaded=True) app.run(host="0.0.0.0", port=app_port, threaded=True)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass
finally: finally:

View File

@@ -9,18 +9,18 @@ import time
import zipfile import zipfile
from datetime import datetime, timedelta from datetime import datetime, timedelta
import requests
from packaging.version import Version from packaging.version import Version
from tabulate import tabulate from tabulate import tabulate
import requests
from build_agent import build_agent_version from build_agent import build_agent_version
from zeroconf_server import ZeroconfServer from zeroconf_server import ZeroconfServer
DEFAULT_PORT = 9001
TIMEOUT = 10 TIMEOUT = 10
def find_server_ips(): def find_server_ips():
ZeroconfServer.configure("_crosspybuilder._tcp.local.", socket.gethostname(), 9001) ZeroconfServer.configure("_crosspybuilder._tcp.local.", socket.gethostname(), DEFAULT_PORT)
hostnames = [] hostnames = []
try: try:
ZeroconfServer.start(listen_only=True) ZeroconfServer.start(listen_only=True)
@@ -32,32 +32,44 @@ def find_server_ips():
ZeroconfServer.stop() ZeroconfServer.stop()
# get known hosts # get known hosts
with open("known_hosts", "r") as file: with open("../known_hosts", "r") as file:
lines = file.readlines() lines = file.readlines()
lines = [line.split(':')[0].strip() for line in lines]
hostnames.extend(lines) hostnames.extend(lines)
return hostnames return hostnames
def get_all_servers_status(): def get_all_servers_status():
table_data = [] table_data = []
server_ips = find_server_ips() server_ips = find_server_ips()
with concurrent.futures.ThreadPoolExecutor() as executor: with concurrent.futures.ThreadPoolExecutor() as executor:
results = executor.map(get_worker_status, server_ips) # Runs in parallel futures = []
table_data.extend(results) for server in server_ips:
ip = server.split(':')[0]
port = server.split(":")[-1].strip() if ":" in server else DEFAULT_PORT
futures.append(executor.submit(get_worker_status, ip, port))
for future in concurrent.futures.as_completed(futures):
try:
result = future.result() # Get the result of the thread
table_data.append(result)
except Exception as e:
print(f"Error fetching status from server: {e}") # Handle potential errors
return table_data return table_data
def get_worker_status(hostname):
def get_worker_status(hostname, port=DEFAULT_PORT):
"""Fetch worker status from the given hostname.""" """Fetch worker status from the given hostname."""
try: try:
response = requests.get(f"http://{hostname}:9001/status", timeout=TIMEOUT) response = requests.get(f"http://{hostname}:{port}/status", timeout=TIMEOUT)
status = response.json() status = response.json()
status['port'] = port
if status['hostname'] != hostname and status['ip'] != hostname: if status['hostname'] != hostname and status['ip'] != hostname:
status['ip'] = socket.gethostbyname(hostname) status['ip'] = socket.gethostbyname(hostname)
return status return status
except requests.exceptions.RequestException as e: except requests.exceptions.RequestException as e:
return {"hostname": hostname, "status": "offline"} return {"hostname": hostname, "port": port, "status": "offline"}
def zip_project(source_dir, output_zip): def zip_project(source_dir, output_zip):
@@ -72,26 +84,36 @@ def zip_project(source_dir, output_zip):
zipf.write(file_path, os.path.relpath(file_path, source_dir)) zipf.write(file_path, os.path.relpath(file_path, source_dir))
def send_build_request(zip_file, server_ip, download_after=False): def send_build_request(server_ip, server_port=DEFAULT_PORT, zip_file=None, git_url=None, download_after=True, version=None):
"""Uploads the zip file to the given server."""
upload_url = f"http://{server_ip}:9001/upload" if zip_file:
print(f"Submitting build request to URL: {upload_url} - Please wait. This may take a few minutes...") upload_url = f"http://{server_ip}:{server_port}/upload"
with open(zip_file, 'rb') as f: print(f"Submitting build request to URL: {upload_url} - Please wait. This may take a few minutes...")
response = requests.post(upload_url, files={"file": f}) with open(zip_file, 'rb') as f:
response = requests.post(upload_url, files={"file": f})
elif git_url:
checkout_url = f"http://{server_ip}:{server_port}/checkout_git"
response = requests.post(checkout_url, json={"repo_url": git_url})
else:
raise ValueError("Missing zip file or git url!")
if response.status_code == 200: if response.status_code == 200:
response_data = response.json() response_data = response.json()
print(response_data)
print(f"Build successful. ID: {response_data['id']} Hostname: {response_data['hostname']} OS: {response_data['os']} CPU: {response_data['cpu']} Spec files: {len(response_data['spec_files'])} - Elapsed time: {response_data['duration']}" ) print(f"Build successful. ID: {response_data['id']} Hostname: {response_data['hostname']} OS: {response_data['os']} CPU: {response_data['cpu']} Spec files: {len(response_data['spec_files'])} - Elapsed time: {response_data['duration']}" )
if download_after: if download_after:
download_url = f"http://{server_ip}:9001/download/{response_data.get('id')}" download_url = f"http://{server_ip}:{server_port}/download/{response_data.get('id')}"
try: try:
save_name = f"{os.path.splitext(os.path.basename(zip_file))[0]}-{response_data['os'].lower()}-{response_data['cpu'].lower()}.zip" base_name = os.path.splitext(os.path.basename(zip_file))[0]
version_string = ("-" + version) if version else ""
save_name = f"{base_name}{version_string}-{response_data['os'].lower()}-{response_data['cpu'].lower()}.zip"
download_zip(download_url, save_name=save_name) download_zip(download_url, save_name=save_name)
except Exception as e: except Exception as e:
print(f"Error downloading zip: {e}") print(f"Error downloading zip: {e}")
else: else:
print("Upload failed:", response.status_code, response.text) print("Upload failed:", response.status_code, response.text)
def download_zip(url, save_name, save_dir="."): def download_zip(url, save_name, save_dir="."):
"""Download a ZIP file from a URL and save it with its original filename.""" """Download a ZIP file from a URL and save it with its original filename."""
response = requests.get(url, stream=True) response = requests.get(url, stream=True)
@@ -116,6 +138,7 @@ def select_server(servers, cpu=None, os_name=None):
available = [s for s in available if os_name.lower() in s["os"].lower()] available = [s for s in available if os_name.lower() in s["os"].lower()]
return available[0] if available else None # Return first matching server or None return available[0] if available else None # Return first matching server or None
def process_new_job(args, server_data): def process_new_job(args, server_data):
available_servers = [s for s in server_data if s["status"] == "ready"] available_servers = [s for s in server_data if s["status"] == "ready"]
@@ -139,19 +162,23 @@ def process_new_job(args, server_data):
print(f"Found {len(available_servers)} servers available to build") print(f"Found {len(available_servers)} servers available to build")
print(tabulate(available_servers, headers="keys", tablefmt="grid")) print(tabulate(available_servers, headers="keys", tablefmt="grid"))
project_path = args.build zip_file = None
tmp_dir = tempfile.gettempdir() if args.build:
zip_file = os.path.join(tmp_dir, f"{os.path.basename(project_path)}.zip") project_path = args.build
zip_project(project_path, zip_file) tmp_dir = tempfile.gettempdir()
print(f"Zipped {project_path} to {zip_file}") zip_file = os.path.join(tmp_dir, f"{os.path.basename(project_path)}.zip")
zip_project(project_path, zip_file)
print(f"Zipped {project_path} to {zip_file}")
# Start builds on all matching servers # Start builds on all matching servers
with concurrent.futures.ThreadPoolExecutor() as executor: with concurrent.futures.ThreadPoolExecutor() as executor:
print("Submitting builds to:") print("Submitting builds to:")
download = True
for server in available_servers: for server in available_servers:
print(f"\t{server['hostname']} - {server['os']} - {server['cpu']}") print(f"\t{server['hostname']} - {server['os']} - {server['cpu']}")
futures = {executor.submit(send_build_request, zip_file, server["ip"], args.download): server for server in futures = {executor.submit(
available_servers} send_build_request,server["ip"], DEFAULT_PORT, zip_file, args.checkout, download, args.version):
server for server in available_servers}
# Collect results # Collect results
for future in concurrent.futures.as_completed(futures): for future in concurrent.futures.as_completed(futures):
@@ -162,16 +189,18 @@ def process_new_job(args, server_data):
print(f"Build failed on {server['hostname']}: {e}") print(f"Build failed on {server['hostname']}: {e}")
try: try:
os.remove(zip_file) if zip_file:
os.remove(zip_file)
except Exception as e: except Exception as e:
print(f"Error removing zip file: {e}") print(f"Error removing zip file: {e}")
def delete_cache(server_data): def delete_cache(server_data):
available_servers = [s for s in server_data if s["status"] == "ready"] available_servers = [s for s in server_data if s["status"] == "ready"]
print(f"Deleting cache in from all available servers ({len(available_servers)})") print(f"Deleting cache in from all available servers ({len(available_servers)})")
for server in available_servers: for server in available_servers:
try: try:
response = requests.get(f"http://{server['ip']}:9001/delete_cache") response = requests.get(f"http://{server['ip']}:{server.get('port', DEFAULT_PORT)}/delete_cache")
response.raise_for_status() response.raise_for_status()
print(f"Cache cleared on {server['hostname']}") print(f"Cache cleared on {server['hostname']}")
except Exception as e: except Exception as e:
@@ -182,18 +211,19 @@ def update_worker(server):
try: try:
print(f"Updating {server['hostname']} from {server.get('agent_version')} => {build_agent_version}") print(f"Updating {server['hostname']} from {server.get('agent_version')} => {build_agent_version}")
with open("build_agent.py", "rb") as file1, open("requirements.txt", "rb") as file2: with open("build_agent.py", "rb") as file1, open("../requirements.txt", "rb") as file2:
update_files = { update_files = {
"file1": open("build_agent.py", "rb"), "file1": open("build_agent.py", "rb"),
"file2": open("requirements.txt", "rb") "file2": open("../requirements.txt", "rb")
} }
response = requests.post(f"http://{server['ip']}:9001/update", files=update_files) response = requests.post(f"http://{server['ip']}:{server.get('port', DEFAULT_PORT)}/update",
files=update_files)
response.raise_for_status() response.raise_for_status()
response_json = response.json() response_json = response.json()
if response_json.get('updated_files') and not response_json.get('error_files'): if response_json.get('updated_files') and not response_json.get('error_files'):
try: try:
requests.get(f"http://{server['ip']}:9001/restart", timeout=TIMEOUT) requests.get(f"http://{server['ip']}:{server.get('port', DEFAULT_PORT)}/restart", timeout=TIMEOUT)
except requests.exceptions.ConnectionError: except requests.exceptions.ConnectionError:
pass pass
return server return server
@@ -227,7 +257,7 @@ def update_build_workers(server_data):
while unverified_servers and datetime.now() < end_time: while unverified_servers and datetime.now() < end_time:
for server_ip in list(unverified_servers.keys()): # Iterate over a copy to avoid modification issues for server_ip in list(unverified_servers.keys()): # Iterate over a copy to avoid modification issues
try: try:
response = requests.get(f"http://{server_ip}:9001/status") response = requests.get(f"http://{server_ip}:{server.get('port', DEFAULT_PORT)}/status")
response.raise_for_status() response.raise_for_status()
server_info = unverified_servers[server_ip] # Get full server details server_info = unverified_servers[server_ip] # Get full server details
agent_version = response.json().get('agent_version') agent_version = response.json().get('agent_version')
@@ -246,23 +276,42 @@ def update_build_workers(server_data):
print("Update complete") print("Update complete")
def shutdown_agent(hostname):
print(f"Shutting down hostname: {hostname}")
try:
requests.get(f"http://{hostname}:{DEFAULT_PORT}/shutdown", timeout=TIMEOUT)
except (requests.exceptions.ConnectionError, TimeoutError):
pass
def restart_agent(hostname):
print(f"Restarting agent: {hostname}")
try:
requests.get(f"http://{hostname}:{DEFAULT_PORT}/restart", timeout=TIMEOUT)
except (requests.exceptions.ConnectionError, TimeoutError):
pass
def main(): def main():
parser = argparse.ArgumentParser(description="Build agent manager for cross-py-builder") parser = argparse.ArgumentParser(description="Build agent manager for cross-py-builder")
parser.add_argument("--status", action="store_true", help="Get status of available servers") parser.add_argument("--status", action="store_true", help="Get status of available servers")
parser.add_argument("--build", type=str, help="Path to the project to build") parser.add_argument("--build", type=str, help="Path to the project to build")
parser.add_argument("--checkout", type=str, help="Url to Git repo for checkout")
parser.add_argument("-cpu", type=str, help="CPU architecture") parser.add_argument("-cpu", type=str, help="CPU architecture")
parser.add_argument("-os", type=str, help="Operating system") parser.add_argument("-os", type=str, help="Operating system")
parser.add_argument("-d", '--download', action="store_true", help="Download after build") parser.add_argument("-version", type=str, help="Version number for build")
parser.add_argument("--delete-cache", action="store_true", help="Delete cache") parser.add_argument("--delete-cache", action="store_true", help="Delete cache")
parser.add_argument("--update-all", action="store_true", help="Update build agent") parser.add_argument("--update-all", action="store_true", help="Update build agent")
parser.add_argument("--restart", type=str, help="Hostname to restart") parser.add_argument("--restart", type=str, help="Hostname to restart")
parser.add_argument("--restart-all", action="store_true", help="Restart all agents") parser.add_argument("--restart-all", action="store_true", help="Restart all agents")
parser.add_argument("--shutdown", type=str, help="Hostname to shutdown") parser.add_argument("--shutdown", type=str, help="Hostname to shutdown")
parser.add_argument("--shutdown-all", action="store_true", help="Restart all agents") parser.add_argument("--shutdown-all", action="store_true", help="Shutdown all agents")
args = parser.parse_args() args = parser.parse_args()
if args.status: if args.status:
print(tabulate(get_all_servers_status(), headers="keys", tablefmt="grid")) server_data = get_all_servers_status()
server_data = [x for x in server_data if x['status'] != 'offline']
print(tabulate(server_data, headers="keys", tablefmt="grid"))
return return
elif args.restart: elif args.restart:
restart_agent(args.restart) restart_agent(args.restart)
@@ -278,27 +327,13 @@ def main():
shutdown_agent(server_ip) shutdown_agent(server_ip)
elif args.delete_cache: elif args.delete_cache:
delete_cache(get_all_servers_status()) delete_cache(get_all_servers_status())
elif args.build: elif args.build or args.checkout:
process_new_job(args, get_all_servers_status()) process_new_job(args, get_all_servers_status())
elif args.update_all: elif args.update_all:
update_build_workers(get_all_servers_status()) update_build_workers(get_all_servers_status())
else: else:
print("No path given!") print("No path given!")
def shutdown_agent(hostname):
print(f"Shutting down hostname: {hostname}")
try:
requests.get(f"http://{hostname}:9001/shutdown", timeout=TIMEOUT)
except (requests.exceptions.ConnectionError, TimeoutError):
pass
def restart_agent(hostname):
print(f"Restarting agent: {hostname}")
try:
requests.get(f"http://{hostname}:9001/restart", timeout=TIMEOUT)
except (requests.exceptions.ConnectionError, TimeoutError):
pass
if __name__ == "__main__": if __name__ == "__main__":
main() main()

View File

@@ -53,7 +53,6 @@ class ZeroconfServer:
@classmethod @classmethod
def _register_service(cls): def _register_service(cls):
try: try:
info = ServiceInfo( info = ServiceInfo(
cls.service_type, cls.service_type,
f"{cls.server_name}.{cls.service_type}", f"{cls.server_name}.{cls.service_type}",

26
setup.py Normal file
View File

@@ -0,0 +1,26 @@
from setuptools import setup, find_packages
setup(
name="cross-py-builder",
version="0.0.1",
packages=find_packages(),
install_requires=open("requirements.txt").read().splitlines(),
entry_points={
"console_scripts": [
"cross-py-agent=cross_py_builder.build_agent:main",
"cross-py-builder=cross_py_builder.agent_manager:main",
],
},
author="Brett Williams",
author_email="blw1138@mac.com",
description="A cross-platform Python build system using PyInstaller",
long_description=open("README.md").read(),
long_description_content_type="text/markdown",
url="https://github.com/blw1138/cross-py-builder",
classifiers=[
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
],
python_requires='>=3.10',
)