def compile_src(creator_name: str,
                src_dir: str,
                build_dir: str,
                mods_dir: str,
                mod_name: str = "Untitled") -> None:
    """
    Packages your mod into a proper mod file. It creates 2 mod files, a full mod file which contains all the files
    in the source folder unchanged along with the compiled python versions next to uncompiled ones and a slim mod-file
    which contains only the compiled versions.

    Modified from andrew's code.
    https://sims4studio.com/thread/15145/started-python-scripting

    :param creator_name: The creators name
    :param src_dir: Source dir for the mod files
    :param build_dir: Place to put the mod files
    :param mods_dir: Place to an extra copy of the slim mod file for testing
    :param mod_name: Name to call the mod
    :return: Nothing
    """

    # Prepend creator name to mod name
    mod_name = creator_name + '_' + mod_name
    mods_sub_dir = os.path.join(mods_dir, mod_name)

    # Create ts4script paths
    ts4script_full_build_path = os.path.join(build_dir,
                                             mod_name + '.ts4script')
    ts4script_mod_path = os.path.join(mods_sub_dir, mod_name + '.ts4script')

    print("Clearing out old builds...")

    # Delete and re-create build and sub-folder in Mods
    is_devmode = symlink_exists_win("", mods_dir, mod_name)
    symlink_remove_win("", mods_dir, mod_name)

    if is_devmode:
        print("Exiting Dev Mode...")

    remove_dir(build_dir)

    ensure_path_created(build_dir)
    ensure_path_created(mods_sub_dir)

    print("Re-building mod...")

    # Compile the mod
    zf = PyZipFile(ts4script_full_build_path,
                   mode='w',
                   compression=ZIP_STORED,
                   allowZip64=True,
                   optimize=2)
    compile_full(src_dir, zf)
    zf.close()

    # Copy it over to the mods folder
    shutil.copyfile(ts4script_full_build_path, ts4script_mod_path)

    print("----------")
    print("Complete")
def debug_teardown(mods_dir: str, mod_folder_name: str) -> None:
    """
    Deletes the 2 mods, they technically cause the running game to slow down

    :param mods_dir: Path to mods directory
    :param mod_folder_name: Name of mod Subfolder
    :return: Nothing
    """

    print("Removing the debugging mod files...")
    mods_sub_dir = os.path.join(mods_dir, mod_folder_name)
    remove_dir(mods_sub_dir)
Exemplo n.º 3
0
def symlink_remove_win(creator_name: str,
                       mods_dir: str,
                       mod_name: str = "Untitled") -> None:
    """
    Safely removes the Mod Name Folder
    /Mods/ModName/

    This is very critical! In order to use symlinks on Windows without requiring admin privs we have to use
    "Directory Junctions", it's a special type of symlink intended for different purposes but works for our case.
    However Python doesn't support Directory Junctions, in fact it can't tell the difference between a directory
    junction and a real folder, it thinks they're the same.

    This means if you don't safely remove the Scripts directory junction, the original source code files the dev is
    working on will be wiped out irrecoverably when doing a re-compile or a re-devmode-setup. In other words, the dev
    will forever lose all the files they were working on as part of their project unless they had a backup elsewhere.
    Their hard work vanishes before their eyes just like that.

    This is unnacceptable, to have a safety process in check, this function removes the mod folder, safely removing
    the scripts folder beforehand. If it's unable to it creates a crash so as to not proceed.

    Always use this function to remove the Mod Name Folder

    :param creator_name: Creator Name
    :param mods_dir: Path to the Mods Folder
    :param mod_name: Name of Mod
    :return: Nothing
    """

    # Build paths
    scripts_path = get_scripts_path(creator_name, mods_dir, mod_name)
    mod_folder_path = str(Path(scripts_path).parent)

    # Check whether the Scripts folder exists
    exists = symlink_exists_win(creator_name, mods_dir, mod_name)

    # Delete the Scripts folder and check whether it was successful
    success = exec_cmd("rmdir", '"' + scripts_path + '"')

    # If the Scripts folder exists but could not be deleted then print an error message and raise an exception
    if exists and not success:
        print("")
        print(
            "Error: Scripts folder exists but can't be removed... Did you create a Scripts folder inside the Mod "
            "Folder at: ")
        print(scripts_path)
        print("If so, please manually delete it and try again.")
        print("")
        raise

    # Otherwise remove the directory
    remove_dir(mod_folder_path)
Exemplo n.º 4
0
import os
import sys

from Utility.helpers_decompile import decompile_pre, decompile_zips, decompile_print_totals
from Utility.helpers_path import ensure_path_created, remove_dir
from settings import gameplay_folder_data, gameplay_folder_game, projects_python_path

if os.path.exists(projects_python_path):
    print("This will wipe out the old decompilation at: " +
          projects_python_path)
    answer = input("Are you sure you want to do this? [y/n]: ")
    if answer is not "y":
        sys.exit("Program aborted by user")

print("Emptying prior decompilation...")
remove_dir(projects_python_path)

# Make sure the python folder exists
ensure_path_created(projects_python_path)

# Do a pre-setup
decompile_pre()

# Decompile all zips to the python projects folder
print("")
print("Beginning decompilation")
print("THIS WILL SERIOUSLY TAKE A VERY LONG TIME!!! " +
      "Additionally many files will not decompile properly which is normal.")
print("")

decompile_zips(gameplay_folder_data, projects_python_path)
Exemplo n.º 5
0
#    Copyright 2020 June Hanabi
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.
import shutil
from Utility.helpers_debug import debug_teardown
from Utility.helpers_path import remove_dir
from Utility.helpers_symlink import symlink_remove_win
from settings import mods_folder, debug_mod_subfolder, creator_name, project_name, build_path

print("Removing Debug Setup...")
debug_teardown(mods_folder, debug_mod_subfolder)

print("Removing Mod Folder in Mods...")
symlink_remove_win(creator_name, mods_folder, project_name)

print("Removing Build folder...")
remove_dir(build_path)

print("")
print("Complete... All build artifacts have been removed!")
def debug_install_egg(egg_path: str, mods_dir, dest_name: str,
                      mod_folder_name: str) -> None:
    """
    Copies the debug egg provided by Pycharm Pro which adds the capability to make debugging happen inside of
    PyCharm Pro. A bit of work goes into this so it'll be much slower.

    :param egg_path: Path to the debug egg
    :param mods_dir: Path to the mods folder
    :param dest_name: Name of the mod
    :param mod_folder_name: Name of mod Subfolder
    :return:
    """

    print("Re-packaging and installing the debugging capability mod...")
    # Get egg filename and path
    filename = Path(egg_path).name
    mods_sub_dir = os.path.join(mods_dir, mod_folder_name)
    mod_path = os.path.join(mods_sub_dir, dest_name + ".ts4script")

    ensure_path_created(mods_sub_dir)

    # Get python ctypes folder
    sys_ctypes_folder = os.path.join(get_sys_folder(), "Lib", "ctypes")

    # Create temp directory
    tmp_dir = tempfile.TemporaryDirectory()
    tmp_egg = tmp_dir.name + os.sep + filename

    # Remove old mod in mods folder there, if it exists
    remove_file(mod_path)

    # Copy egg to temp path
    shutil.copyfile(egg_path, tmp_egg)

    # Extract egg
    # This step is a bit redundant but I need to copy over everything but one folder into the zip file and I don't
    # know how to do that in python so I copy over the zip, extract it, copy in the whole folder, delete the one
    # sub-folder, then re-zip everything up. It's a pain but it's what I know hwo to do now and Google's not much help
    zip = PyZipFile(tmp_egg)
    zip.extractall(tmp_dir.name)
    zip.close()

    # Remove archive
    remove_file(tmp_egg)

    # Copy ctype folder to extracted archive
    shutil.copytree(sys_ctypes_folder, tmp_dir.name + os.sep + "ctypes")

    # Remove that one folder
    remove_dir(tmp_dir.name + os.sep + "ctypes" + os.sep + "__pycache__")

    # Grab a handle on the egg
    zf = PyZipFile(mod_path,
                   mode='w',
                   compression=ZIP_STORED,
                   allowZip64=True,
                   optimize=2)

    # Add all the files in the tmp directory to the zip file
    for folder, subs, files in os.walk(tmp_dir.name):
        for file in files:
            archive_path = get_rel_path(folder + os.sep + file, tmp_dir.name)
            zf.write(folder + os.sep + file, archive_path)

    zf.close()

    # There's a temporary directory bug that causes auto-cleanup to sometimes fail
    # We're preventing crash messages from flooding the screen to keep things tidy
    try:
        tmp_dir.cleanup()
    except:
        pass