Skip to content
This repository has been archived by the owner on Sep 20, 2024. It is now read-only.

Add rez packages generation for server_addons #6169

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Temporary Items
/build
/dist/
/server_addon/packages/*
/server_addon/rez_packages/*

/vendor/bin/*
/vendor/python/*
Expand Down
201 changes: 133 additions & 68 deletions server_addon/create_ayon_addons.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# Skip directories starting with '.'
r"^\.",
# Skip any pycache folders
"^__pycache__$"
"^__pycache__$",
}
]

Expand All @@ -29,7 +29,7 @@
# NOTE this could be an issue in some cases
r"^\.",
# Skip '.pyc' files
r"\.pyc$"
r"\.pyc$",
}
]

Expand All @@ -56,6 +56,7 @@ class ZipFileLongPaths(zipfile.ZipFile):
That limit can be exceeded by using an extended-length path that
starts with the '\\?\' prefix.
"""

_is_windows = platform.system().lower() == "windows"

def _extract_member(self, member, tpath, pwd):
Expand All @@ -72,17 +73,14 @@ def _extract_member(self, member, tpath, pwd):


def _value_match_regexes(value: str, regexes: Iterable[Pattern]) -> bool:
return any(
regex.search(value)
for regex in regexes
)
return any(regex.search(value) for regex in regexes)


def find_files_in_subdir(
src_path: str,
ignore_file_patterns: Optional[List[Pattern]] = None,
ignore_dir_patterns: Optional[List[Pattern]] = None,
ignore_subdirs: Optional[Iterable[Tuple[str]]] = None
ignore_subdirs: Optional[Iterable[Tuple[str]]] = None,
):
"""Find all files to copy in subdirectories of given path.

Expand Down Expand Up @@ -151,18 +149,32 @@ def create_addon_zip(
output_dir: Path,
addon_name: str,
addon_version: str,
keep_source: bool
keep_source: bool,
rez_package: bool,
):
zip_filepath = output_dir / f"{addon_name}-{addon_version}.zip"
if rez_package:
zip_filepath = output_dir / f"{addon_name}-{addon_version}-rez.zip"
else:
zip_filepath = output_dir / f"{addon_name}-{addon_version}.zip"
addon_output_dir = output_dir / addon_name / addon_version

with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
zipf.writestr(
"manifest.json",
json.dumps({
"addon_name": addon_name,
"addon_version": addon_version
})
)
if not rez_package:
zipf.writestr(
"manifest.json",
json.dumps(
{"addon_name": addon_name, "addon_version": addon_version}
),
)
else:
zipf.writestr(
"package.py",
f"""name = "{addon_name}"
version = "{addon_version}"
plugin_for = ["ayon_server"]
build_command = "python {{root}}/rezbuild.py"
""",
)
# Add client code content to zip
src_root = os.path.normpath(str(addon_output_dir.absolute()))
src_root_offset = len(src_root) + 1
Expand All @@ -174,9 +186,16 @@ def create_addon_zip(
for filename in filenames:
src_path = os.path.join(root, filename)
if rel_root:
dst_path = os.path.join("addon", rel_root, filename)
if rez_package:
dst_path = os.path.join(rel_root, filename)
else:
dst_path = os.path.join("addon", rel_root, filename)
else:
dst_path = os.path.join("addon", filename)
if rez_package:
dst_path = os.path.join(root, filename)
else:
dst_path = os.path.join("addon", filename)

zipf.write(src_path, dst_path)

if not keep_source:
Expand All @@ -188,7 +207,8 @@ def create_openpype_package(
output_dir: Path,
root_dir: Path,
create_zip: bool,
keep_source: bool
keep_source: bool,
rez_package: bool,
):
server_dir = addon_dir / "server"
pyproject_path = addon_dir / "client" / "pyproject.toml"
Expand All @@ -198,82 +218,114 @@ def create_openpype_package(
addon_version = read_addon_version(version_path)

addon_output_dir = output_dir / "openpype" / addon_version
private_dir = addon_output_dir / "private"
# Clean up any previous "build"
if addon_output_dir.exists():
shutil.rmtree(str(addon_output_dir))

# Make sure dir exists
addon_output_dir.mkdir(parents=True, exist_ok=True)
private_dir.mkdir(parents=True, exist_ok=True)

# Copy version
shutil.copy(str(version_path), str(addon_output_dir))
for subitem in server_dir.iterdir():
shutil.copy(str(subitem), str(addon_output_dir / subitem.name))
if not rez_package:
# Copy version
shutil.copy(str(version_path), str(addon_output_dir))
for subitem in server_dir.iterdir():
dest = addon_output_dir / subitem.name
shutil.copy(str(subitem), str(addon_output_dir / subitem.name))

private_dir = addon_output_dir / "private"
private_dir.mkdir(parents=True, exist_ok=True)
# Copy pyproject.toml
shutil.copy(str(pyproject_path), (private_dir / pyproject_path.name))

else:
shutil.copytree(addon_dir, addon_output_dir, dirs_exist_ok=True)
# Copy pyproject.toml
shutil.copy(
str(pyproject_path),
(addon_output_dir / "client" / pyproject_path.name),
)

# Copy pyproject.toml
shutil.copy(
str(pyproject_path),
(private_dir / pyproject_path.name)
)
# Subdirs that won't be added to output zip file
ignored_subpaths = [
["addons"],
["vendor", "common", "ayon_api"],
]
ignored_subpaths.extend(
["hosts", host_name]
for host_name in IGNORED_HOSTS
["hosts", host_name] for host_name in IGNORED_HOSTS
)
ignored_subpaths.extend(
["modules", module_name]
for module_name in IGNORED_MODULES
["modules", module_name] for module_name in IGNORED_MODULES
)

# Zip client
zip_filepath = private_dir / "client.zip"
with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
# Add client code content to zip
if not rez_package:
# Zip client
zip_filepath = private_dir / "client.zip"
with ZipFileLongPaths(zip_filepath, "w", zipfile.ZIP_DEFLATED) as zipf:
# Add client code content to zip
for path, sub_path in find_files_in_subdir(
str(openpype_dir), ignore_subdirs=ignored_subpaths
):
zipf.write(path, f"{openpype_dir.name}/{sub_path}")
else:
for path, sub_path in find_files_in_subdir(
str(openpype_dir), ignore_subdirs=ignored_subpaths
):
zipf.write(path, f"{openpype_dir.name}/{sub_path}")
dest = addon_output_dir / "client" / sub_path
os.makedirs(os.path.dirname(dest), exist_ok=True)
shutil.copy(path, addon_output_dir / "client" / sub_path)

if create_zip:
create_addon_zip(output_dir, "openpype", addon_version, keep_source)
create_addon_zip(
output_dir, "openpype", addon_version, keep_source, rez_package
)


def create_addon_package(
addon_dir: Path,
output_dir: Path,
create_zip: bool,
keep_source: bool
keep_source: bool,
rez_package: bool,
):
server_dir = addon_dir / "server"
addon_version = get_addon_version(addon_dir)

addon_output_dir = output_dir / addon_dir.name / addon_version

if addon_output_dir.exists():
shutil.rmtree(str(addon_output_dir))
addon_output_dir.mkdir(parents=True)

# Copy server content
src_root = os.path.normpath(str(server_dir.absolute()))
src_root_offset = len(src_root) + 1
for root, _, filenames in os.walk(str(server_dir)):
dst_root = addon_output_dir
if root != src_root:
rel_root = root[src_root_offset:]
dst_root = dst_root / rel_root

dst_root.mkdir(parents=True, exist_ok=True)
for filename in filenames:
src_path = os.path.join(root, filename)
shutil.copy(src_path, str(dst_root))
if not rez_package:
src_root = os.path.normpath(str(server_dir.absolute()))
src_root_offset = len(src_root) + 1
for root, _, filenames in os.walk(str(server_dir)):
dst_root = addon_output_dir
if root != src_root:
rel_root = root[src_root_offset:]
dst_root = dst_root / rel_root

dst_root.mkdir(parents=True, exist_ok=True)
for filename in filenames:
src_path = os.path.join(root, filename)
shutil.copy(src_path, str(dst_root))
else:
package_py = addon_output_dir / "package.py"

with open(package_py, "w+") as pkg_py:
pkg_py.write(
f"""name = "{addon_dir.name}"
version = "{addon_version}"
plugin_for = ["ayon_server"]
build_command = "python {{root}}/rezbuild.py"
"""
)
shutil.copytree(
server_dir, addon_output_dir / "server", dirs_exist_ok=True
)

if create_zip:
create_addon_zip(
output_dir, addon_dir.name, addon_version, keep_source
output_dir, addon_dir.name, addon_version, keep_source, rez_package
)


Expand All @@ -283,6 +335,7 @@ def main(
keep_source=False,
clear_output_dir=False,
addons=None,
rez_package=False,
):
current_dir = Path(os.path.dirname(os.path.abspath(__file__)))
root_dir = current_dir.parent
Expand Down Expand Up @@ -318,12 +371,17 @@ def main(

if addon_dir.name == "openpype":
create_openpype_package(
addon_dir, output_dir, root_dir, create_zip, keep_source
addon_dir,
output_dir,
root_dir,
create_zip,
keep_source,
rez_package,
)

else:
create_addon_package(
addon_dir, output_dir, create_zip, keep_source
addon_dir, output_dir, create_zip, keep_source, rez_package
)

print(f"- package '{addon_dir.name}' created")
Expand All @@ -339,32 +397,30 @@ def main(
help=(
"Skip zipping server package and create only"
" server folder structure."
)
),
)
parser.add_argument(
"--keep-sources",
dest="keep_sources",
action="store_true",
help=(
"Keep folder structure when server package is created."
)
help=("Keep folder structure when server package is created."),
)
parser.add_argument(
"-o", "--output",
"-o",
"--output",
dest="output_dir",
default=None,
help=(
"Directory path where package will be created"
" (Will be purged if already exists!)"
)
),
)
parser.add_argument(
"-c", "--clear-output-dir",
"-c",
"--clear-output-dir",
dest="clear_output_dir",
action="store_true",
help=(
"Clear output directory before package creation."
)
help=("Clear output directory before package creation."),
)
parser.add_argument(
"-a",
Expand All @@ -374,11 +430,20 @@ def main(
help="Limit addon creation to given addon name",
)

parser.add_argument(
"-r",
"--rez",
dest="rez_package",
action="store_true",
help="Make it a Rez-compatible package",
)

args = parser.parse_args(sys.argv[1:])
main(
args.output_dir,
args.skip_zip,
args.keep_sources,
args.clear_output_dir,
args.addons,
args.rez_package,
)
Loading