diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a90da24..f0a55a9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,10 +10,29 @@ on: # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: + Check python package: + runs-on: ubuntu-latest + steps: + - name: Checkout this Repo + uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: 3.7 + + - name: Install Dependencies + run: | + pip install -r requirements.txt + pip install pylint + + - name: Check formatting + run: pylint rmskin_builder.py + Build: + # needs: Checkpython package runs-on: ubuntu-latest steps: - # Checkout code - name: Checkout this Repo uses: actions/checkout@v2 @@ -25,8 +44,8 @@ jobs: - name: Run Build action id: builder uses: 2bndy5/rmskin-action@master - # with: - # path: ${{ github.workspace }} + with: + path: ${{ github.workspace }}/tests # Use the output from the `builder` step - name: Print the output filename diff --git a/.gitignore b/.gitignore index 080024b..1e7c1ca 100644 --- a/.gitignore +++ b/.gitignore @@ -124,4 +124,7 @@ dmypy.json .pyre/ # vscode folder -.vscode/ \ No newline at end of file +.vscode/ + +# ignore local test's output files +*.rmskin diff --git a/Dockerfile b/Dockerfile index 03fd40f..c837c65 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,9 +3,9 @@ FROM python:latest # Copies your code file from your action repository to the filesystem path `/` of the container COPY enter_rmskin_builder.sh /enter_rmskin_builder.sh -COPY release.py /rmskin_builder.py +COPY rmskin_builder.py /rmskin_builder.py COPY requirements.txt /reqs.txt RUN chmod +x /enter_rmskin_builder.sh # Code file to execute when the docker container starts up (`enter_rmskin_builder.sh`) -ENTRYPOINT ["/enter_rmskin_builder.sh"] \ No newline at end of file +ENTRYPOINT ["/enter_rmskin_builder.sh"] diff --git a/README.rst b/README.rst index a06a3d1..7090569 100644 --- a/README.rst +++ b/README.rst @@ -2,14 +2,14 @@ .. image:: https://github.com/2bndy5/rmskin-action/workflows/CI/badge.svg :target: https://github.com/2bndy5/rmskin-action/actions - rmskin-action ============= A Python-based Github action tool to package a Repository's Rainmeter Content into a validating .rmskin file for Rainmeter's Skin Installer. -.. important:: If the repository contains a RMSKIN.bmp image to used as a header image in the rmskin package, then it must be using 24-bit colors. Additionally, if the image is not exactly 400x60, then this action's python script will resize it accordingly. - +.. important:: + If the repository contains a RMSKIN.bmp image to used as a header image in the rmskin package, then it must be using 24-bit colors. + Additionally, if the image is not exactly 400x60, then this action's python script will resize it accordingly. Input Arguments =============== @@ -24,7 +24,7 @@ Input Arguments "path", "Base directory of repo being packaged. Defaults to workflow's workspace path", "no" "dir_out", "Path to save generated rmskin package. Defaults to workflow's workspace path", "no" - .. note:: + .. note:: You can use your repository's ``RMSKIN.ini`` file to override any above inputs except ``dir_out`` & ``path`` inputs. Output Arguments @@ -33,18 +33,34 @@ Output Arguments * ``arc_name`` : The name of the generated rmskin file saved in the path specified by ``dir_out`` input argument. +Ideal Repo Structure +==================== + +- root directory + + * ``Skins`` <- a folder to contain all necessary Rainmeter skins + * ``RMSKIN.ini`` <- list of options specific to installing the skin(s) + * ``Layouts`` <- a folder that contains Rainmeter layout files + * ``Plugins`` <- a folder that contains Rainmeter plugins + * ``@Vault`` <- resources folder accessible by all installed skins + +.. seealso:: + `A cookiecutter repository `_ + has also been created to facilitate development of Rainmeter skins on Github + quickly. + Example Usage ============= .. code-block:: yaml - + name: RMSKIN Packager - on: + on: push: pull_request: release: - types: + types: - published jobs: @@ -64,7 +80,7 @@ Example Usage # Use the output from the `builder` step - name: Print the output filename run: echo "The output file was ${{ steps.builder.outputs.arc_name }}" - + # get release upload_url - name: Get Release id: get_release @@ -75,7 +91,7 @@ Example Usage # Upload the asset - name: Upload Release Asset - id: upload-release-asset + id: upload-release-asset uses: actions/upload-release-asset@v1 if: github.event_name == 'release' env: @@ -85,4 +101,3 @@ Example Usage asset_path: ./${{ steps.builder.outputs.arc_name }} asset_name: ${{ steps.builder.outputs.arc_name }} asset_content_type: application/zip - diff --git a/release.py b/release.py deleted file mode 100644 index 2ab3045..0000000 --- a/release.py +++ /dev/null @@ -1,260 +0,0 @@ -""" -A script to run on github release action that will -attempt to assemble a validating Rainmeter skin -package for quick and easy distibution. - -ideal repo structure -******************** - - - root directory - * ``Skins`` (a folder to contain all necessary skins) - * ``RMSKIN.ini`` (list of options specific to installing the - skin). - * ``Layouts``(a folder that contains rainmeter layout files) - * ``Plugins``(a folder that contains rainmeter plugins) - * ``@Vault`` (resources folder accessible by all installed - skins) -""" -import os -import argparse -import configparser -import zipfile -import struct -import pefile -from PIL import Image - -parser = argparse.ArgumentParser( - description=""" - A script that will attempt to assemble a - validating Rainmeter skin package for - quick and easy githuib distibution.""" -) -parser.add_argument( - "--path", - metavar='"STR"', - type=str, - default=os.getenv("GITHUB_WORKSPACE", os.getcwd()), - help="Base path of a git repository. Defaults to working directory.", -) -parser.add_argument( - "--version", - metavar='"STR"', - type=str, - default='auto', - help="Version of release. This should be the github action env var (GITHUB_REF - 'refs/tags' or last 8 digits of GITHUB_SHA).", -) -parser.add_argument( - "--author", - metavar='"STR"', - type=str, - default="Unknown", - help="Author of release. This should be the github action env var (GITHUB_ACTOR).", -) -parser.add_argument( - "--title", - metavar='"STR"', - type=str, - default=os.getcwd().split(os.sep)[len(os.getcwd().split(os.sep)) - 1], - help="Title of released package. This should be just the github repo name.", -) -parser.add_argument( - "--dir_out", - metavar='"STR"', - type=str, - default=None, - help="Output path to save released package file. This optional & only used when specified.", -) - -HAS_COMPONENTS = { - "RMSKIN.ini": False, - "Skins": 0, - "Layouts": 0, - "Plugins": False, - "@Vault": 0, - "RMSKIN.bmp": False -} - - -def main(): - # collect cmd args - args = parser.parse_args() - root_path = args.path - # truncate trailing path seperator - if root_path.endswith(os.sep): - root_path = root_path[:-1] - if args.dir_out is not None and args.dir_out.endswith(os.sep): - args.dir_out = args.dir_out[:-1] - print(f"using path: {root_path}") - - # capture the directory tree - for dirpath, dirnames, filenames in os.walk(root_path): - dirpath = dirpath.replace(root_path, "") - if dirpath.endswith("Skins"): - HAS_COMPONENTS["Skins"] = len(dirnames) - print(f"Found {HAS_COMPONENTS['Skins']} possible Skin(s)") - elif dirpath.endswith("@Vault"): - HAS_COMPONENTS["@Vault"] = len(filenames) + len(dirnames) - print(f"Found {HAS_COMPONENTS['@Vault']} possible @Vault item(s)") - elif dirpath.endswith("Plugins"): - if len(dirnames) > 0: - HAS_COMPONENTS["Plugins"] = True - print("Found Plugins folder") - elif dirpath.endswith("Layouts"): - HAS_COMPONENTS["Layouts"] = len(filenames) + len(dirnames) - print(f"Found {HAS_COMPONENTS['Layouts']} possible Layout(s)") - elif len(dirpath) == 0: - if "RMSKIN.ini" in filenames: - HAS_COMPONENTS["RMSKIN.ini"] = True - print("Found RMSKIN.ini file") - if "RMSKIN.bmp" in filenames: - HAS_COMPONENTS["RMSKIN.bmp"] = True - print("Found header image") - for d in dirnames: # exclude hidden directories - if d.startswith("."): - del d - # set depth of search to shallow (2 folders deep) - if len(dirpath) > 0: - dirnames.clear() - - # quite if bad dir struct - if not ( - HAS_COMPONENTS["Layouts"] - or HAS_COMPONENTS["Skins"] - or HAS_COMPONENTS["Plugins"] - or HAS_COMPONENTS["@Vault"] - ): - raise RuntimeError( - f"repository structure for {root_path} is malformed. Found no Skins," - " Layouts, or Plugins!" - ) - # read options from RMSKIN.ini - arc_name = args.title - version = args.version - config = configparser.ConfigParser() - if HAS_COMPONENTS["RMSKIN.ini"]: - config.read(root_path + os.sep + "RMSKIN.ini") - if "rmskin" in config: - if "Version" in config["rmskin"]: - version = config["rmskin"]["Version"] - if version.endswith("auto"): - if not os.getenv("GITHUB_REF", "").startswith("refs/tags/"): - version = os.getenv("GITHUB_SHA", "x0x.x0xy")[-8:] - else: - version = os.getenv("GITHUB_REF", "refs/tags/0.0").replace("refs/tags/", "") - config["rmskin"]["Version"] = version - if not "Author" in config["rmskin"]: - # maybe someday aggregated list authors from discovered skins' metadata->Author fields - config["rmskin"]["Author"] = args.author - if "Name" in config["rmskin"]: - # use hard-coded name - arc_name = config["rmskin"]["Name"] - else: - # use repo name - config["rmskin"]["Name"] = args.title - print(f"Using Name ({arc_name}) & Version ({version})") - load_t = config["rmskin"]["LoadType"] # ex: "Skin" - load = config["rmskin"]["Load"] # ex: "Skin_Root\\skin.ini" - # for cross-platform compatibility, adjust windows-style path seperators - load = load.replace("\\", os.sep) - if len(load_t): # if a file set to load on-install - # exit early if loaded file does not exist - with open( - root_path + os.sep + load_t + "s" + os.sep + (load if load_t == "Skin" else load + os.sep + "Rainmeter.ini"), "r" - ) as temp: - if temp is None: - raise RuntimeError("On-install loaded file does not exits.") - else: - raise RuntimeError("RMSKIN.ini is malformed") - with open(root_path + os.sep + "RMSKIN.ini", "w") as conf: - config.write(conf) # Dump changes/corrections back2file - else: - raise RuntimeError( - f"repository structure for {root_path} is malformed. RMSKIN.ini file not found!" - ) - - # make sure header image is correct size (400x60) & correct color space - if HAS_COMPONENTS["RMSKIN.bmp"]: - with Image.open(root_path + os.sep + "RMSKIN.bmp") as img: - if img.width != 400 and img.height != 60: - print("WARNING: resizing header image to 400x60") - img = img.resize((400, 60)) - if img.mode != 'RGB': - print("Correcting color space in header image.") - img = img.convert(mode='RGB') - img.save(root_path + os.sep + "RMSKIN.bmp") - - # Now creating the archive - compressed_size = 0 - with zipfile.ZipFile( - (root_path if args.dir_out is None else args.dir_out) - + os.sep + arc_name + "_" + version + ".rmskin", - "w", - compression=zipfile.ZIP_DEFLATED, - compresslevel=9, - ) as arc_file: - # write RMSKIN.ini and header image (RMSKIN.bmp) first - if HAS_COMPONENTS["RMSKIN.bmp"]: - arc_file.write(root_path + os.sep + "RMSKIN.bmp", arcname="RMSKIN.bmp") - arc_file.write(root_path + os.sep + "RMSKIN.ini", arcname="RMSKIN.ini") - for key in HAS_COMPONENTS: - if key.endswith(".ini"): - pass - elif HAS_COMPONENTS[key]: - for dirpath, dirnames, filenames in os.walk(root_path + os.sep + key): - if key.endswith("Plugins"): - # check bitness of plugins here & archive accordingly - for n in filenames: - if n.lower().endswith(".dll"): - # let plugin_name be 2nd last folder name in dll's path - bitness = pefile.PE( - dirpath + os.sep + n, - fast_load=True, # just get headers - ) - bitness.close() # do this now to copy file safely later - # pylint: disable=no-member - if bitness.FILE_HEADER.Machine == 0x014C: - # archive this 32-bit plugin - arc_file.write( - dirpath + os.sep + n, - arcname=key + os.sep + "32bit" + os.sep + n, - ) - else: - # archive this 64-bit plugin - arc_file.write( - dirpath + os.sep + n, - arcname=key + os.sep + "64bit" + os.sep + n, - ) - # pylint: enable=no-member - del bitness - else: # for misc files in plugins folders like READMEs - arc_file.write( - dirpath + os.sep + n, - arcname=dirpath.replace(root_path + os.sep, "") - + os.sep - + n, - ) - else: - for n in filenames: - arc_file.write( - dirpath + os.sep + n, - arcname=dirpath.replace(root_path + os.sep, "") - + os.sep - + n, - ) - # archive assembled; closing file - compressed_size = os.path.getsize(arc_name + "_" + version + ".rmskin") - print(f"archive size = {compressed_size} ({hex(compressed_size)})") - # convert size to a bytes obj & prepend to custom footer - custom_footer = struct.pack("q", compressed_size) + b"\x00RMSKIN\x00" - - # append footer to archive - with open(arc_name + "_" + version + ".rmskin", "a+b") as arc_file: - print(f"appending footer: {custom_footer}") - arc_file.write(custom_footer) - - print("Archive successfully prepared.") - print("::set-output name=arc_name::{}".format(arc_name + "_" + version + ".rmskin")) - - -if __name__ == "__main__": - main() diff --git a/rmskin_builder.py b/rmskin_builder.py new file mode 100644 index 0000000..4fdf621 --- /dev/null +++ b/rmskin_builder.py @@ -0,0 +1,332 @@ +#! /usr/bin/python3 +""" +A script that will attempt to assemble a validating Rainmeter skin package for +quick and easy distibution on Github. + +Ideal Repo Structure +******************** + +- root directory + + * ``Skins`` <- a folder to contain all necessary Rainmeter skins + * ``RMSKIN.ini`` <- list of options specific to installing the skin(s) + * ``Layouts`` <- a folder that contains Rainmeter layout files + * ``Plugins`` <- a folder that contains Rainmeter plugins + * ``@Vault`` <- resources folder accessible by all installed skins + +.. seealso:: + `A cookiecutter repository `_ + has also been created to facilitate development of Rainmeter skins on Github + quickly. +""" +import os +import argparse +import configparser +import zipfile +import struct +import logging +import pefile +from PIL import Image + + +parser = argparse.ArgumentParser( + description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter +) +parser.add_argument( + "--path", + metavar='"str"', + type=str, + default=os.getenv("GITHUB_WORKSPACE", os.getcwd()), + help="Base path of a git repository. Defaults to working directory.", +) +parser.add_argument( + "--version", + metavar='"str"', + type=str, + default="auto", + help="Version of release. This should be the github action env var " + "GITHUB_REF ('refs/tags') or last 8 digits of GITHUB_SHA.", +) +parser.add_argument( + "--author", + metavar='"str"', + type=str, + default="Unknown", + help="Author of release. This should be the github action env var GITHUB_ACTOR.", +) +parser.add_argument( + "--title", + metavar='"str"', + type=str, + default=os.path.split(os.getcwd())[1], + help="Title of released package. This should be just the github repo name.", +) +parser.add_argument( + "--dir_out", + metavar='"str"', + type=str, + default=None, + help="Output path to save released package file. This optional & only used when specified.", +) + +# setup logging output +logging.basicConfig() +LOGGER_NAME = os.path.split(__file__)[1].split(".")[0].split("_") +LOGGER_NAME[0] = LOGGER_NAME[0].upper() +LOGGER_NAME[1] = LOGGER_NAME[1].title() +LOGGER_NAME = " ".join(LOGGER_NAME) +logger = logging.getLogger(LOGGER_NAME) +logger.setLevel(logging.INFO) + +#: The `dict` of package components discovered by the `main()` loop +HAS_COMPONENTS = { + "RMSKIN.ini": False, + "Skins": 0, + "Layouts": 0, + "Plugins": False, + "@Vault": 0, + "RMSKIN.bmp": False, +} + + +def discover_components(): + """The method that does priliminary dscovery of rmskin package components.""" + for dirpath, dirnames, filenames in os.walk(root_path): + dirpath = dirpath.replace(root_path, "") + if dirpath.endswith("Skins"): + HAS_COMPONENTS["Skins"] = len(dirnames) + logger.info("Found %d possible Skin(s)", HAS_COMPONENTS["Skins"]) + elif dirpath.endswith("@Vault"): + HAS_COMPONENTS["@Vault"] = len(filenames) + len(dirnames) + logger.info("Found %d possible @Vault item(s)", HAS_COMPONENTS["@Vault"]) + elif dirpath.endswith("Plugins"): + if len(dirnames) > 0: + HAS_COMPONENTS["Plugins"] = True + logger.info("Found Plugins folder") + elif dirpath.endswith("Layouts"): + HAS_COMPONENTS["Layouts"] = len(filenames) + len(dirnames) + logger.info("Found %d possible Layout(s)", HAS_COMPONENTS["Layouts"]) + elif len(dirpath) == 0: + if "RMSKIN.ini" in filenames: + HAS_COMPONENTS["RMSKIN.ini"] = True + logger.info("Found RMSKIN.ini file") + if "RMSKIN.bmp" in filenames: + HAS_COMPONENTS["RMSKIN.bmp"] = True + logger.info("Found header image") + for dir_name in dirnames: # exclude hidden directories + if dir_name.startswith("."): + del dir_name + # set depth of search to shallow (2 folders deep) + if len(dirpath) > 0: + dirnames.clear() + + +def parse_rmskin_ini(): + """Read the RMSKIN.ini and write a copy for building the RMSKIN package.""" + arc_name = args.title + version = args.version + config = configparser.ConfigParser() + + config.read(root_path + os.sep + "RMSKIN.ini") + if "rmskin" in config: + if "Version" in config["rmskin"]: + version = config["rmskin"]["Version"] + if version.endswith("auto"): + if not os.getenv("GITHUB_REF", "").startswith("refs/tags/"): + version = os.getenv("GITHUB_SHA", "x0x.x0xy")[-8:] + else: + version = os.getenv("GITHUB_REF", "refs/tags/0.0").replace( + "refs/tags/", "" + ) + config["rmskin"]["Version"] = version + if not "Author" in config["rmskin"]: + # maybe someday, aggregate list of authors from + # discovered skins' metadata->Author fields + config["rmskin"]["Author"] = args.author + if "Name" in config["rmskin"]: + # use hard-coded name + arc_name = config["rmskin"]["Name"] + else: + # use repo name + config["rmskin"]["Name"] = args.title + logger.info("Using Name (%s) & Version (%s)", arc_name, version) + load_t = config["rmskin"]["LoadType"] # ex: "Skin" + load = config["rmskin"]["Load"] # ex: "Skin_Root\\skin.ini" + # for cross-platform compatibility, adjust windows-style path seperators + load = load.replace("\\", os.sep) + if len(load_t): # if a file set to load on-install + # exit early if loaded file does not exist + temp = ( + root_path + + os.sep + + load_t + + "s" + + os.sep + + (load if load_t == "Skin" else load + os.sep + "Rainmeter.ini") + ) + if not os.path.isfile(temp): + raise RuntimeError("On-install loaded file does not exits.") + else: + raise RuntimeError("RMSKIN.ini is malformed") + with open(BUILD_DIR + "RMSKIN.ini", "w") as conf: + config.write(conf) # Dump changes/corrections to temp build dir + return (arc_name, version) + + +def validate_header_image(): + """Make sure header image (if any) is ready to package""" + if HAS_COMPONENTS["RMSKIN.bmp"]: + with Image.open(root_path + os.sep + "RMSKIN.bmp") as img: + if img.width != 400 and img.height != 60: + logger.warning("Resizing header image to 400x60") + img = img.resize((400, 60)) + if img.mode != "RGB": + logger.warning("Correcting color space in header image.") + img = img.convert(mode="RGB") + img.save(BUILD_DIR + "RMSKIN.bmp") + + +def init_zip_for_package(arch_name): + """Create initial archive to use as RMSKIN package""" + # pylint: disable=too-many-nested-blocks + output_path_to_archive = ( + (root_path if args.dir_out is None else args.dir_out) + os.sep + arch_name + ) + with zipfile.ZipFile( + output_path_to_archive, + "w", + compression=zipfile.ZIP_DEFLATED, + compresslevel=9, + ) as arc_file: + # write RMSKIN.ini and header image (RMSKIN.bmp) first + if HAS_COMPONENTS["RMSKIN.bmp"]: + arc_file.write(BUILD_DIR + "RMSKIN.bmp", arcname="RMSKIN.bmp") + arc_file.write(BUILD_DIR + "RMSKIN.ini", arcname="RMSKIN.ini") + for key, val in HAS_COMPONENTS.items(): + if not key.endswith(".ini") and val: + for dirpath, _, filenames in os.walk(root_path + os.sep + key): + if key.endswith("Plugins"): + # check bitness of plugins here & archive accordingly + for file_name in filenames: + if file_name.lower().endswith(".dll"): + # let plugin_name be 2nd last folder name in dll's path + bitness = pefile.PE( + dirpath + os.sep + file_name, + fast_load=True, # just get headers + ) + bitness.close() # do this now to copy file safely later + # pylint: disable=no-member + if bitness.FILE_HEADER.Machine == 0x014C: + # archive this 32-bit plugin + arc_file.write( + dirpath + os.sep + file_name, + arcname=key + + os.sep + + "32bit" + + os.sep + + file_name, + ) + # pylint: enable=no-member + else: + # archive this 64-bit plugin + arc_file.write( + dirpath + os.sep + file_name, + arcname=key + + os.sep + + "64bit" + + os.sep + + file_name, + ) + del bitness + else: # for misc files in plugins folders like READMEs + arc_file.write( + dirpath + os.sep + file_name, + arcname=dirpath.replace(root_path + os.sep, "") + + os.sep + + file_name, + ) + else: + for file_name in filenames: + arc_file.write( + dirpath + os.sep + file_name, + arcname=dirpath.replace(root_path + os.sep, "") + + os.sep + + file_name, + ) + # archive assembled; closing file + # pylint: enable=too-many-nested-blocks + return output_path_to_archive + +def main(): + """The main execution loop for creating a rmskin package.""" + logger.info("Searching path: %s", root_path) + + # capture the directory tree + discover_components() + + # quit if bad dir struct + if not ( + HAS_COMPONENTS["Layouts"] + or HAS_COMPONENTS["Skins"] + or HAS_COMPONENTS["Plugins"] + or HAS_COMPONENTS["@Vault"] + ): + raise RuntimeError( + f"repository structure for {root_path} is malformed. Found no Skins," + " Layouts, Plugins, or @Vault assets." + ) + + # quit if no RMSKIN.ini + if not HAS_COMPONENTS["RMSKIN.ini"]: + raise RuntimeError( + f"repository structure for {root_path} is malformed. RMSKIN.ini file " + "not found." + ) + + # read options from RMSKIN.ini + arc_name, version = parse_rmskin_ini() + + # make sure header image is correct size (400x60) & correct color space + validate_header_image() + + # Now creating the archive + archive_name = arc_name + "_" + version + ".rmskin" + path_to_archive = init_zip_for_package(archive_name) + + compressed_size = 0 + compressed_size = os.path.getsize(path_to_archive) + logger.info("archive size = %d (0x%X)", compressed_size, compressed_size) + + # convert size to a bytes obj & prepend to custom footer + custom_footer = struct.pack("q", compressed_size) + b"\x00RMSKIN\x00" + + # append footer to archive + with open(path_to_archive, "a+b") as arc_file: + logger.debug("appending footer: %s", repr(custom_footer)) + arc_file.write(custom_footer) + logger.info("Archive successfully prepared.") + + # env var CI is always true when executed on a github action runner + if os.getenv("CI", "false").title().startswith("True"): + print("::set-output name=arc_name::{}".format(archive_name)) + else: + logger.info("archive name: %s", archive_name) + + +if __name__ == "__main__": + # collect cmd args + args = parser.parse_args() + root_path = args.path + # truncate trailing path seperator + if root_path.endswith(os.sep): + root_path = root_path[:-1] + root_path = os.path.abspath(root_path) + + # The temporary build dir for storing altered files + BUILD_DIR = root_path + os.sep + "build" + os.sep + if not os.path.isdir(BUILD_DIR): + os.mkdir(BUILD_DIR) + + if args.dir_out is not None and args.dir_out.endswith(os.sep): + args.dir_out = args.dir_out.rstrip(os.sep) + main() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..49b8403 --- /dev/null +++ b/setup.py @@ -0,0 +1,45 @@ +"""A setuptools based setup module. + +See: +https://packaging.python.org/en/latest/distributing.html +https://github.com/pypa/sampleproject +""" +import os +from codecs import open as open_codec # To use a consistent encoding +from setuptools import setup + + +ROOT_DIR = os.path.abspath(os.path.dirname(__file__)) +REPO = "https://github.com/2bndy5/rmskin-action" + +# Get the long description from the README file +with open_codec(os.path.join(ROOT_DIR, "README.rst"), encoding="utf-8") as f: + long_description = f.read() + +setup( + name="rmskin-action", + use_scm_version=True, + setup_requires=["setuptools_scm"], + description="A script that will attempt to assemble a validating Rainmeter skin " + "package for quick and easy distibution on Github.", + long_description=long_description, + long_description_content_type="text/x-rst", + author="Brendan Doherty", + author_email="2bndy5@gmail.com", + install_requires=["pefile", "pillow"], + license="MIT", + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Topic :: System :: Archiving :: Packaging", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + ], + keywords="rainmeter rmskin archive builder", + py_modules=["rmskin_builder"], + scripts=["./rmskin_builder.py"], + # Specifiy your homepage URL for your project here + url=REPO, + download_url=f"{REPO}/releases", +) diff --git a/@Vault/picture.jpg b/tests/@Vault/picture.jpg similarity index 100% rename from @Vault/picture.jpg rename to tests/@Vault/picture.jpg diff --git a/Layouts/Test.ini b/tests/Layouts/Test.ini similarity index 100% rename from Layouts/Test.ini rename to tests/Layouts/Test.ini diff --git a/Plugins/Test/32bit/ConfigActive.dll b/tests/Plugins/Test/32bit/ConfigActive.dll similarity index 100% rename from Plugins/Test/32bit/ConfigActive.dll rename to tests/Plugins/Test/32bit/ConfigActive.dll diff --git a/Plugins/Test/64bit/ConfigActive.dll b/tests/Plugins/Test/64bit/ConfigActive.dll similarity index 100% rename from Plugins/Test/64bit/ConfigActive.dll rename to tests/Plugins/Test/64bit/ConfigActive.dll diff --git a/RMSKIN.bmp b/tests/RMSKIN.bmp similarity index 100% rename from RMSKIN.bmp rename to tests/RMSKIN.bmp diff --git a/RMSKIN.ini b/tests/RMSKIN.ini similarity index 100% rename from RMSKIN.ini rename to tests/RMSKIN.ini diff --git a/Skins/Test/test.ini b/tests/Skins/Test/test.ini similarity index 100% rename from Skins/Test/test.ini rename to tests/Skins/Test/test.ini