648 lines
24 KiB
Python
Executable File
648 lines
24 KiB
Python
Executable File
import hashlib
|
|
import io
|
|
import json
|
|
import os
|
|
import platform
|
|
import sys
|
|
import time
|
|
import aiohttp
|
|
import git
|
|
import folder_paths
|
|
import server
|
|
import os
|
|
import pkg_resources
|
|
from typing import Callable
|
|
from aiohttp import web
|
|
from aiohttp_retry import ExponentialRetry, RetryClient
|
|
from tqdm.asyncio import tqdm
|
|
from .exports import generate_export_json_file
|
|
|
|
|
|
NODE_CLASS_MAPPINGS = {}
|
|
NODE_DISPLAY_NAME_MAPPINGS = {}
|
|
|
|
|
|
WEB_DIRECTORY = "./web"
|
|
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
|
|
|
comfy_path = os.path.dirname(folder_paths.__file__)
|
|
custom_nodes_path = os.path.join(comfy_path, 'custom_nodes')
|
|
|
|
CW_ENDPOINT = os.environ.get("CW_ENDPOINT", "https://comfyworkflows.com")
|
|
|
|
|
|
def get_current_snapshot():
|
|
# Get ComfyUI hash (credit to ComfyUI-Manager for this function)
|
|
repo_path = os.path.dirname(folder_paths.__file__)
|
|
|
|
if not os.path.exists(os.path.join(repo_path, '.git')):
|
|
print(f"ComfyUI update fail: The installed ComfyUI does not have a Git repository.")
|
|
return web.Response(status=400)
|
|
|
|
repo = git.Repo(repo_path)
|
|
comfyui_commit_hash = repo.head.commit.hexsha
|
|
|
|
git_custom_nodes = {}
|
|
file_custom_nodes = []
|
|
|
|
# Get custom nodes hash
|
|
for path in os.listdir(custom_nodes_path):
|
|
fullpath = os.path.join(custom_nodes_path, path)
|
|
|
|
if os.path.isdir(fullpath):
|
|
is_disabled = path.endswith(".disabled")
|
|
|
|
try:
|
|
git_dir = os.path.join(fullpath, '.git')
|
|
|
|
if not os.path.exists(git_dir):
|
|
continue
|
|
|
|
repo = git.Repo(fullpath)
|
|
commit_hash = repo.head.commit.hexsha
|
|
url = repo.remotes.origin.url
|
|
git_custom_nodes[url] = {
|
|
'hash': commit_hash,
|
|
'disabled': is_disabled
|
|
}
|
|
|
|
except:
|
|
print(f"Failed to extract snapshots for the custom node '{path}'.")
|
|
|
|
elif path.endswith('.py'):
|
|
is_disabled = path.endswith(".py.disabled")
|
|
filename = os.path.basename(path)
|
|
item = {
|
|
'filename': filename,
|
|
'disabled': is_disabled
|
|
}
|
|
|
|
file_custom_nodes.append(item)
|
|
|
|
return {
|
|
'comfyui': comfyui_commit_hash,
|
|
'git_custom_nodes': git_custom_nodes,
|
|
'file_custom_nodes': file_custom_nodes,
|
|
}
|
|
|
|
def get_file_sha256_checksum(file_path):
|
|
BUF_SIZE = 65536 # lets read stuff in 64kb chunks!
|
|
sha256 = hashlib.sha256()
|
|
with open(file_path, 'rb') as f:
|
|
while True:
|
|
data = f.read(BUF_SIZE)
|
|
if not data:
|
|
break
|
|
sha256.update(data)
|
|
return sha256.hexdigest()
|
|
|
|
def extract_file_names(json_data):
|
|
"""Extract unique file names from the input JSON data."""
|
|
file_names = set()
|
|
|
|
# Recursively search for file names in the JSON data
|
|
def recursive_search(data):
|
|
if isinstance(data, dict):
|
|
for value in data.values():
|
|
recursive_search(value)
|
|
elif isinstance(data, list):
|
|
for item in data:
|
|
recursive_search(item)
|
|
elif isinstance(data, str) and '.' in data:
|
|
file_names.add(os.path.basename(data)) # file_names.add(data)
|
|
|
|
recursive_search(json_data)
|
|
return list(file_names)
|
|
|
|
def find_file_paths(base_dir, file_names):
|
|
"""Find the paths of the files in the base directory."""
|
|
file_paths = {}
|
|
|
|
for root, dirs, files in os.walk(base_dir, followlinks=True):
|
|
# Exclude certain directories
|
|
dirs[:] = [d for d in dirs if d not in ['.git']]
|
|
|
|
for file in files:
|
|
if file in file_names:
|
|
file_paths[file] = os.path.join(root, file)
|
|
return file_paths
|
|
|
|
|
|
class CallbackBytesIO(io.BytesIO):
|
|
|
|
def __init__(self, callback: Callable, initial_bytes: bytes):
|
|
self._callback = callback
|
|
super().__init__(initial_bytes)
|
|
|
|
def read(self, size=-1) -> bytes:
|
|
data = super().read(size)
|
|
self._callback(len(data))
|
|
return data
|
|
|
|
DEPLOY_PROGRESS = {}
|
|
EXPORT_PROGRESS = {}
|
|
|
|
@server.PromptServer.instance.routes.get("/cw/upload_progress")
|
|
async def api_comfyworkflows_upload_progress(request):
|
|
global DEPLOY_PROGRESS
|
|
return web.json_response(DEPLOY_PROGRESS)
|
|
|
|
@server.PromptServer.instance.routes.get("/cw/export_progress")
|
|
async def api_comfyworkflows_export_progress(request):
|
|
global EXPORT_PROGRESS
|
|
return web.json_response(EXPORT_PROGRESS)
|
|
|
|
UPLOAD_CHUNK_SIZE = 100_000_000 # 100 MB
|
|
|
|
def get_num_chunks(file_size):
|
|
global UPLOAD_CHUNK_SIZE
|
|
num_chunks = file_size // UPLOAD_CHUNK_SIZE
|
|
if file_size % UPLOAD_CHUNK_SIZE != 0:
|
|
num_chunks += 1
|
|
return num_chunks
|
|
|
|
@server.PromptServer.instance.routes.get("/comfyui_interface")
|
|
async def get_comfyui_interface(request):
|
|
print(os.path.join(server.PromptServer.instance.web_root, "comfyui_index.html"))
|
|
return web.FileResponse(os.path.join(server.PromptServer.instance.web_root, "comfyui_index.html"))
|
|
|
|
@server.PromptServer.instance.routes.get("/cw/current_graph")
|
|
async def api_comfyworkflows_current_graph(request):
|
|
current_file_directory = os.path.dirname(os.path.abspath(__file__))
|
|
current_graph_filepath = os.path.join(current_file_directory, "current_graph.json")
|
|
if not os.path.exists(current_graph_filepath):
|
|
return web.Response(status=404)
|
|
return web.json_response(json.load(open(current_graph_filepath, "r")))
|
|
|
|
@server.PromptServer.instance.routes.post("/cw/save_graph")
|
|
async def api_comfyworkflows_save_graph(request):
|
|
json_data = await request.json()
|
|
current_file_directory = os.path.dirname(os.path.abspath(__file__))
|
|
current_graph_filepath = os.path.join(current_file_directory, "current_graph.json")
|
|
with open(current_graph_filepath, "w") as f:
|
|
json.dump(json_data, f)
|
|
return web.Response(status=200)
|
|
|
|
@server.PromptServer.instance.routes.post("/cw/reset_load_default_graph")
|
|
async def api_comfyworkflows_reset_load_default_graph(request):
|
|
current_file_directory = os.path.dirname(os.path.abspath(__file__))
|
|
load_default_graph_filepath = os.path.join(current_file_directory, "load_default_graph.txt")
|
|
if os.path.exists(load_default_graph_filepath):
|
|
os.remove(load_default_graph_filepath)
|
|
return web.Response(status=200)
|
|
|
|
@server.PromptServer.instance.routes.post("/cw/upload")
|
|
async def api_comfyworkflows_upload(request):
|
|
global DEPLOY_PROGRESS
|
|
print("Uploading workflow...")
|
|
json_data = await request.json()
|
|
|
|
code = json_data['code']
|
|
prompt = json_data['prompt']
|
|
filteredNodeTypeToNodeData = json_data['filteredNodeTypeToNodeData']
|
|
|
|
# Example usage
|
|
base_directory = folder_paths.base_path #"./"
|
|
|
|
# Parse the JSON
|
|
parsed_json = prompt
|
|
|
|
DEPLOY_PROGRESS = {
|
|
"status" : "preparing upload...",
|
|
}
|
|
|
|
# TODO: For now, we assume that there are no duplicate files with the same name at 2 or more different paths.
|
|
|
|
# Extract file names
|
|
file_names = set(extract_file_names(parsed_json))
|
|
print("File names: ", file_names)
|
|
|
|
# Find file paths
|
|
file_paths = find_file_paths(base_directory, file_names)
|
|
print("File paths: ", file_paths)
|
|
|
|
all_file_info = {}
|
|
for file_name, file_path in file_paths.items():
|
|
file_checksum = get_file_sha256_checksum(file_path)
|
|
all_file_info[file_name] = {
|
|
'path': file_path,
|
|
'size': os.path.getsize(file_path),
|
|
'dest_relative_path': os.path.relpath(file_path, base_directory),
|
|
'checksum': file_checksum
|
|
}
|
|
|
|
extra_folders_to_upload = [
|
|
]
|
|
for folder in extra_folders_to_upload:
|
|
abs_folder_path = os.path.abspath(folder)
|
|
for root, dirs, files in os.walk(abs_folder_path, followlinks=True):
|
|
for file in files:
|
|
file_path = os.path.join(root, file)
|
|
file_checksum = get_file_sha256_checksum(file_path)
|
|
all_file_info[file] = {
|
|
'path': file_path,
|
|
'size': os.path.getsize(file_path),
|
|
'dest_relative_path': os.path.relpath(file_path, base_directory),
|
|
'checksum': file_checksum
|
|
}
|
|
|
|
total_num_chunks = 0
|
|
for file_name, file_info in all_file_info.items():
|
|
num_chunks = get_num_chunks(file_info['size'])
|
|
total_num_chunks += num_chunks
|
|
|
|
DEPLOY_PROGRESS = {
|
|
"status" : "creating snapshot...",
|
|
}
|
|
|
|
# Compute snapshot
|
|
snapshot_json = get_current_snapshot()
|
|
# print("Current snapshot json:")
|
|
# print(snapshot_json)
|
|
|
|
raise_for_status = {x for x in range(100, 600)}
|
|
raise_for_status.remove(200)
|
|
raise_for_status.remove(429)
|
|
|
|
pip_packages = []
|
|
installed_packages = pkg_resources.working_set
|
|
for package in installed_packages:
|
|
pip_package = package.__dict__
|
|
if "_provider" in pip_package:
|
|
del pip_package["_provider"]
|
|
pip_packages.append(pip_package)
|
|
|
|
# First, create the runnable workflow object
|
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
|
retry_client = RetryClient(session, retry_options=ExponentialRetry(attempts=3), raise_for_status=raise_for_status)
|
|
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/runnable-workflows/init_runnable_workflow",
|
|
json={
|
|
"runnable_workflow_key": code,
|
|
"num_files" : len(all_file_info),
|
|
"workflow_json" : json.dumps(prompt),
|
|
"snapshot_json" : json.dumps(snapshot_json),
|
|
"filteredNodeTypeToNodeData" : json.dumps(filteredNodeTypeToNodeData),
|
|
"pip_packages" : json.dumps(pip_packages) if pip_packages else None,
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
|
|
# Now, we upload each file
|
|
DEPLOY_PROGRESS = {
|
|
"status" : f"uploading files... (0%)",
|
|
}
|
|
total_num_files = len(all_file_info)
|
|
current_file_index = -1
|
|
num_chunks_uploaded = 0
|
|
for file_name, file_info in all_file_info.items():
|
|
# print(f"Going to upload file: {file_name}...")
|
|
DEPLOY_PROGRESS = {
|
|
"status" : f"uploading files... ({round(100.0 * num_chunks_uploaded / total_num_chunks, 2)}%)",
|
|
}
|
|
|
|
num_chunks_for_file = get_num_chunks(file_info['size'])
|
|
current_file_index += 1
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/runnable-workflows/get_presigned_url_for_runnable_workflow_file",
|
|
json={
|
|
"runnable_workflow_key": code,
|
|
"dest_relative_path" : file_info['dest_relative_path'],
|
|
"sha256_checksum": file_info['checksum'],
|
|
'size': file_info['size'],
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
upload_json = await resp.json()
|
|
|
|
if upload_json['uploadFile'] == False:
|
|
print(f"Skipping file {file_name} because it already exists in the cloud.")
|
|
num_chunks_uploaded += num_chunks_for_file
|
|
continue
|
|
|
|
uploadId = upload_json['uploadId']
|
|
presigned_urls = upload_json['signedUrlsList']
|
|
objectKey = upload_json['objectKey']
|
|
|
|
# print(presigned_url)
|
|
# print("Uploading file: {0}".format(file_info['path']))
|
|
t = time.time()
|
|
# headers = {
|
|
# "Content-Length": str(file_info['size']),
|
|
# }
|
|
# print(headers)
|
|
# progress_bar = tqdm(
|
|
# desc=f"Uploading {os.path.basename(file_info['path'])}",
|
|
# unit="B",
|
|
# unit_scale=True,
|
|
# total=file_info['size'],
|
|
# unit_divisor=1024,
|
|
# )
|
|
|
|
# with open(file_info['path'], "rb") as f:
|
|
# file_data = CallbackBytesIO(progress_bar.update, f.read())
|
|
|
|
parts = []
|
|
|
|
progress_bar = tqdm(
|
|
desc=f"Uploading file ({(current_file_index + 1)}/{total_num_files}) {os.path.basename(file_info['path'])}",
|
|
unit="B",
|
|
unit_scale=True,
|
|
total=file_info['size'],
|
|
unit_divisor=1024,
|
|
)
|
|
|
|
with open(file_info['path'], "rb") as f:
|
|
chunk_index = 0
|
|
while True:
|
|
data = f.read(UPLOAD_CHUNK_SIZE)
|
|
if not data:
|
|
# print("Finished uploading file. ", chunk_index, UPLOAD_CHUNK_SIZE)
|
|
break
|
|
|
|
max_retries = 5
|
|
num_retries = 0
|
|
while num_retries < max_retries:
|
|
try:
|
|
async with retry_client.put(presigned_urls[chunk_index],data=data) as resp:
|
|
assert resp.status == 200
|
|
parts.append({
|
|
'ETag': resp.headers['ETag'],
|
|
'PartNumber': chunk_index + 1,
|
|
})
|
|
break
|
|
except:
|
|
num_retries += 1
|
|
# print(f"Failed to upload chunk {chunk_index} of file {file_name} to {presigned_urls[chunk_index]}... retrying ({num_retries}/{max_retries})")
|
|
if num_retries == max_retries:
|
|
raise Exception(f"Failed to upload file {os.path.basename(file_info['path'])} after {max_retries} retries.")
|
|
|
|
progress_bar.update(len(data))
|
|
|
|
chunk_index += 1
|
|
|
|
num_chunks_uploaded += 1
|
|
DEPLOY_PROGRESS = {
|
|
"status" : f"uploading files... ({round(100.0 * num_chunks_uploaded / total_num_chunks, 2)}%)",
|
|
}
|
|
|
|
# Complete the multipart upload for this file
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/runnable-workflows/complete_multipart_upload_for_runnable_workflow_file",
|
|
json={
|
|
"parts": parts,
|
|
"objectKey": objectKey,
|
|
"uploadId": uploadId,
|
|
"runnable_workflow_key": code,
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
# print("Upload took {0} seconds".format(time.time() - t))
|
|
|
|
# One last request to finalize the runnable workflow
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/runnable-workflows/finalize_runnable_workflow",
|
|
json={
|
|
"runnable_workflow_key": code,
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
resp_json = await resp.json()
|
|
workflow_id = resp_json['workflow_id']
|
|
version_id = resp_json['version_id']
|
|
|
|
workflow_deploy_url = f"{CW_ENDPOINT}/workflows/{workflow_id}?version={version_id}"
|
|
DEPLOY_PROGRESS = {}
|
|
print("\n\n")
|
|
print(f"Successfully uploaded workflow: ", workflow_deploy_url)
|
|
|
|
# Now, return a json response with the workflow ID
|
|
return web.json_response({"deploy_url": workflow_deploy_url})
|
|
|
|
|
|
@server.PromptServer.instance.routes.post("/cw/export")
|
|
async def api_comfyworkflows_export(request):
|
|
global EXPORT_PROGRESS
|
|
print("Exporting workflow...")
|
|
json_data = await request.json()
|
|
|
|
prompt = json_data['prompt']
|
|
filteredNodeTypeToNodeData = json_data['filteredNodeTypeToNodeData']
|
|
|
|
# Example usage
|
|
base_directory = folder_paths.base_path #"./"
|
|
|
|
# Parse the JSON
|
|
parsed_json = prompt
|
|
|
|
EXPORT_PROGRESS = {
|
|
"status" : "preparing export...",
|
|
}
|
|
|
|
# TODO: For now, we assume that there are no duplicate files with the same name at 2 or more different paths.
|
|
|
|
# Extract file names
|
|
file_names = set(extract_file_names(parsed_json))
|
|
print("File names: ", file_names)
|
|
|
|
# Find file paths
|
|
file_paths = find_file_paths(base_directory, file_names)
|
|
print("File paths: ", file_paths)
|
|
|
|
all_file_info = {}
|
|
for file_name, file_path in file_paths.items():
|
|
file_checksum = get_file_sha256_checksum(file_path)
|
|
all_file_info[file_name] = {
|
|
'path': file_path,
|
|
'size': os.path.getsize(file_path),
|
|
'dest_relative_path': os.path.relpath(file_path, base_directory),
|
|
'checksum': file_checksum
|
|
}
|
|
|
|
extra_folders_to_upload = [
|
|
]
|
|
for folder in extra_folders_to_upload:
|
|
abs_folder_path = os.path.abspath(folder)
|
|
for root, dirs, files in os.walk(abs_folder_path, followlinks=True):
|
|
for file in files:
|
|
file_path = os.path.join(root, file)
|
|
file_checksum = get_file_sha256_checksum(file_path)
|
|
all_file_info[file] = {
|
|
'path': file_path,
|
|
'size': os.path.getsize(file_path),
|
|
'dest_relative_path': os.path.relpath(file_path, base_directory),
|
|
'checksum': file_checksum
|
|
}
|
|
|
|
total_num_chunks = 0
|
|
for file_name, file_info in all_file_info.items():
|
|
num_chunks = get_num_chunks(file_info['size'])
|
|
total_num_chunks += num_chunks
|
|
|
|
EXPORT_PROGRESS = {
|
|
"status" : "creating snapshot...",
|
|
}
|
|
|
|
# Compute snapshot
|
|
# TODO: Support non-public custom nodes
|
|
snapshot_json = get_current_snapshot()
|
|
|
|
raise_for_status = {x for x in range(100, 600)}
|
|
raise_for_status.remove(200)
|
|
raise_for_status.remove(429)
|
|
|
|
pip_packages = []
|
|
installed_packages = pkg_resources.working_set
|
|
for package in installed_packages:
|
|
pip_package = package.__dict__
|
|
if "_provider" in pip_package:
|
|
del pip_package["_provider"]
|
|
if "location" in pip_package:
|
|
del pip_package["location"]
|
|
pip_packages.append(pip_package)
|
|
|
|
files_data = []
|
|
|
|
# First, create the runnable workflow object
|
|
async with aiohttp.ClientSession(trust_env=True, connector=aiohttp.TCPConnector(verify_ssl=False)) as session:
|
|
retry_client = RetryClient(session, retry_options=ExponentialRetry(attempts=3), raise_for_status=raise_for_status)
|
|
# Now, we upload each file
|
|
EXPORT_PROGRESS = {
|
|
"status" : f"uploading files... (0%)",
|
|
}
|
|
total_num_files = len(all_file_info)
|
|
current_file_index = -1
|
|
num_chunks_uploaded = 0
|
|
for file_name, file_info in all_file_info.items():
|
|
# print(f"Going to upload file: {file_name}...")
|
|
EXPORT_PROGRESS = {
|
|
"status" : f"uploading files... ({round(100.0 * num_chunks_uploaded / total_num_chunks, 2)}%)",
|
|
}
|
|
|
|
num_chunks_for_file = get_num_chunks(file_info['size'])
|
|
current_file_index += 1
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/comfyui-launcher/get_presigned_url_for_launcher_export_file",
|
|
json={
|
|
"dest_relative_path" : file_info['dest_relative_path'],
|
|
"sha256_checksum": file_info['checksum'],
|
|
'size': file_info['size'],
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
upload_json = await resp.json()
|
|
|
|
if upload_json['uploadFile'] == False:
|
|
file_url = upload_json['file_url']
|
|
|
|
print(f"Skipping file {file_name} because it already exists in the cloud.")
|
|
num_chunks_uploaded += num_chunks_for_file
|
|
|
|
files_data.append([{
|
|
"download_url" : file_url,
|
|
"dest_relative_path" : file_info['dest_relative_path'],
|
|
"sha256_checksum" : file_info['checksum'],
|
|
"size" : file_info['size']
|
|
}])
|
|
continue
|
|
|
|
launcher_file_id = upload_json['launcher_file_id']
|
|
uploadId = upload_json['uploadId']
|
|
presigned_urls = upload_json['signedUrlsList']
|
|
objectKey = upload_json['objectKey']
|
|
|
|
t = time.time()
|
|
|
|
parts = []
|
|
|
|
progress_bar = tqdm(
|
|
desc=f"Uploading file ({(current_file_index + 1)}/{total_num_files}) {os.path.basename(file_info['path'])}",
|
|
unit="B",
|
|
unit_scale=True,
|
|
total=file_info['size'],
|
|
unit_divisor=1024,
|
|
)
|
|
|
|
with open(file_info['path'], "rb") as f:
|
|
chunk_index = 0
|
|
while True:
|
|
data = f.read(UPLOAD_CHUNK_SIZE)
|
|
if not data:
|
|
break
|
|
|
|
max_retries = 5
|
|
num_retries = 0
|
|
while num_retries < max_retries:
|
|
try:
|
|
async with retry_client.put(presigned_urls[chunk_index],data=data) as resp:
|
|
assert resp.status == 200
|
|
parts.append({
|
|
'ETag': resp.headers['ETag'],
|
|
'PartNumber': chunk_index + 1,
|
|
})
|
|
break
|
|
except:
|
|
num_retries += 1
|
|
# print(f"Failed to upload chunk {chunk_index} of file {file_name} to {presigned_urls[chunk_index]}... retrying ({num_retries}/{max_retries})")
|
|
if num_retries == max_retries:
|
|
raise Exception(f"Failed to upload file {os.path.basename(file_info['path'])} after {max_retries} retries.")
|
|
|
|
progress_bar.update(len(data))
|
|
|
|
chunk_index += 1
|
|
|
|
num_chunks_uploaded += 1
|
|
EXPORT_PROGRESS = {
|
|
"status" : f"uploading files... ({round(100.0 * num_chunks_uploaded / total_num_chunks, 2)}%)",
|
|
}
|
|
|
|
# Complete the multipart upload for this file
|
|
async with retry_client.post(
|
|
f"{CW_ENDPOINT}/api/comfyui-launcher/complete_multipart_upload_for_launcher_file",
|
|
json={
|
|
"parts": parts,
|
|
"objectKey": objectKey,
|
|
"uploadId": uploadId,
|
|
"launcher_file_id" : launcher_file_id
|
|
},
|
|
) as resp:
|
|
assert resp.status == 200
|
|
resp_json = await resp.json()
|
|
file_url = resp_json['file_url']
|
|
# print("Upload took {0} seconds".format(time.time() - t))
|
|
|
|
files_data.append([{
|
|
"download_url" : file_url,
|
|
"dest_relative_path" : file_info['dest_relative_path'],
|
|
"sha256_checksum" : file_info['checksum'],
|
|
"size" : file_info['size']
|
|
}])
|
|
|
|
export_json = generate_export_json_file(
|
|
workflow_json=parsed_json,
|
|
snapshot_json=snapshot_json,
|
|
files_data=files_data,
|
|
pip_reqs=pip_packages,
|
|
os_type={
|
|
"name" : os.name,
|
|
"platform" : platform.system()
|
|
},
|
|
python_version={
|
|
"version" : platform.sys.version,
|
|
"version_info" : {
|
|
"major": sys.version_info.major,
|
|
"minor": sys.version_info.minor,
|
|
"micro": sys.version_info.micro,
|
|
"releaselevel": sys.version_info.releaselevel,
|
|
"serial": sys.version_info.serial,
|
|
}
|
|
}
|
|
)
|
|
|
|
EXPORT_PROGRESS = {}
|
|
print("\n\n")
|
|
print(f"Successfully exported workflow.")
|
|
|
|
# Now, return a json response with the workflow ID
|
|
return web.json_response(export_json) |