diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..31b347b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ + +Changelog +========= + +1.0.0 (2016-04-21) + +* Initial stable release. diff --git a/README.md b/README.md index 97ca96a..d6ea7d5 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,24 @@ # FOMOD Validator +[![Build status](https://ci.appveyor.com/api/projects/status/3p22luum2qhnoc54?svg=true)](https://ci.appveyor.com/project/GandaG/fomod-validator) *Validate your FOMOD installers.* ## Overview -*TODO* +This little app allows you validate and check for common errors in your FOMOD installers. Simply place the path to your package (the source files) and press `Ok` and, according to your selections, it will provide with your results. Simple, easy and effective. + +## Download + +Get either the [latest stable release](https://github.com/GandaG/fomod-validator/releases/latest) or, for the more daring, the [bleeding edge release](https://ci.appveyor.com/project/GandaG/fomod-validator/build/artifacts). ## Installation -* Download the zip file corresponding to your OS from the [latest release](https://github.com/GandaG/fomod-validator/releases/latest); * Extract the folder within to a location of your choice; * Run the "FOMOD Validator" executable. ## Contributing -This repo uses a ***.settings*** file to define all the necessary settings. This file follows this syntax: +This repo uses a `.settings` file to define all the necessary settings. This file follows this syntax: ``` [git] diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..55d5ceb --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,21 @@ +install: + - .\dev\appveyor-bootstrap.bat + +build: off + +test_script: + - inv build + +artifacts: + - path: dist\* + name: windows_build + +deploy: + - provider: GitHub + auth_token: + secure: iMaZrvVT+OI/9jRs8LyOvmzVqIBa0/jpiK96wNzZww/KqKsMcferhIeSK7faNzOo + artifact: windows_build + description: '[Changelog.](https://github.com/GandaG/fomod-validator/blob/master/CHANGELOG.md)' + force_update: true + on: + appveyor_repo_tag: true diff --git a/dev/appveyor-bootstrap.bat b/dev/appveyor-bootstrap.bat new file mode 100644 index 0000000..3023550 --- /dev/null +++ b/dev/appveyor-bootstrap.bat @@ -0,0 +1,13 @@ +@echo off + +set PATH=C:\Miniconda-x64;C:\Miniconda-x64\Scripts;%PATH% + +conda create -y -n fomod-validator^ + -c https://conda.anaconda.org/mmcauliffe^ + -c https://conda.anaconda.org/anaconda^ + pyqt5=5.5.1 python=3.5.1 lxml=3.5.0 +call activate fomod-validator + +pip install pip -U +pip install setuptools -U --ignore-installed +pip install -r dev\reqs.txt diff --git a/dev/pyinstaller-build.spec b/dev/pyinstaller-build.spec index 9ac3e2d..62d73a9 100644 --- a/dev/pyinstaller-build.spec +++ b/dev/pyinstaller-build.spec @@ -6,7 +6,8 @@ import os a = Analysis(['pyinstaller-bootstrap.py'], pathex=[os.getcwd()], binaries=None, - datas=[('../setup.cfg', '.'),], + datas=[('../setup.cfg', '.'), + ('../resources', 'resources/'),], hiddenimports=[], hookspath=[], runtime_hooks=[], diff --git a/dev/reqs.txt b/dev/reqs.txt index 7f25038..9559420 100644 --- a/dev/reqs.txt +++ b/dev/reqs.txt @@ -1,4 +1,8 @@ bumpversion==0.5.3 invoke==0.12.2 lxml==3.5.0 +pkginfo==1.2.1 PyInstaller==3.1.1 +requests==2.9.1 +requests-toolbelt==0.6.0 +twine==1.6.5 diff --git a/fomod/__main__.py b/fomod/__main__.py index 8d4ae69..d0f8f37 100644 --- a/fomod/__main__.py +++ b/fomod/__main__.py @@ -14,10 +14,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import sys +from PyQt5.QtWidgets import QApplication +from . import exceptions, mainframe + def main(): - pass + sys.excepthook = exceptions.excepthook + app = QApplication(sys.argv) + win = mainframe.Mainframe() + sys.exit(app.exec_()) if __name__ == "__main__": main() diff --git a/fomod/exceptions.py b/fomod/exceptions.py new file mode 100644 index 0000000..9a4ce5a --- /dev/null +++ b/fomod/exceptions.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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 traceback +import io +from PyQt5 import QtWidgets, QtGui +from . import __version__ + + +def excepthook(exc_type, exc_value, tracebackobj): + """ + Global function to catch unhandled exceptions. + + @param exc_type exception type + @param exc_value exception value + @param tracebackobj traceback object + """ + notice = ( + "An unhandled exception occurred. Please report the problem" + " at Github," + " or STEP.") + version_info = __version__ + + tbinfofile = io.StringIO() + traceback.print_tb(tracebackobj, None, tbinfofile) + tbinfofile.seek(0) + tbinfo = tbinfofile.read() + errmsg = 'Error information:\n\nVersion: {}\n{}: {}\n'.format(version_info, str(exc_type), str(exc_value)) + sections = [errmsg, tbinfo] + msg = '\n'.join(sections) + + errorbox = QtWidgets.QMessageBox() + errorbox.setText(notice) + errorbox.setDetailedText(msg) + errorbox.setWindowTitle("Nobody Panic!") + errorbox.exec_() diff --git a/fomod/mainframe.py b/fomod/mainframe.py new file mode 100644 index 0000000..f2df075 --- /dev/null +++ b/fomod/mainframe.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + +from PyQt5 import uic, QtWidgets, QtCore +from os.path import join, expanduser +from . import cur_folder + +base_ui = uic.loadUiType(join(cur_folder, "resources", "mainframe.ui")) + + +class Mainframe(base_ui[0], base_ui[1]): + def __init__(self): + super(Mainframe, self).__init__() + self.setupUi(self) + + self.setWindowFlags(QtCore.Qt.WindowSystemMenuHint | QtCore.Qt.WindowTitleHint) + + self.buttonBox.accepted.connect(self.accepted) + self.buttonBox.rejected.connect(self.rejected) + self.path_button.clicked.connect(self.path_button_clicked) + + self.package_path = "" + self.checked_validate = False + self.checked_warnings = False + + self.show() + + def accepted(self): + from .validator import validate, check_warnings, \ + ValidationError, WarningError, MissingFolderError, MissingFileError + + self.package_path = self.path_text.text() + self.checked_validate = self.check_validate.isChecked() + self.checked_warnings = self.check_warnings.isChecked() + + self.close() + + try: + errorbox = QtWidgets.QMessageBox() + + if self.checked_validate: + validate(self.package_path, cur_folder) + + if self.checked_warnings: + log = check_warnings(self.package_path) + + errorbox.setText("All good!") + errorbox.setWindowTitle("Yay!") + errorbox.exec_() + return + except ValidationError as v: + errorbox.setText(str(v)) + errorbox.setWindowTitle("Invalid File(s)") + errorbox.exec_() + return + except WarningError as w: + errorbox.setText(str(w)) + errorbox.setWindowTitle("Warnings Log") + errorbox.exec_() + return + except (MissingFileError, MissingFolderError) as m: + errorbox.setText(str(m)) + errorbox.setWindowTitle("I/O Error") + errorbox.exec_() + return + + def rejected(self): + self.close() + + def path_button_clicked(self): + open_dialog = QtWidgets.QFileDialog() + self.path_text.setText(open_dialog.getExistingDirectory(self, "Package directory:", expanduser("~"))) diff --git a/fomod/validator/__init__.py b/fomod/validator/__init__.py new file mode 100644 index 0000000..3beb94c --- /dev/null +++ b/fomod/validator/__init__.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + +from .validate import validate +from .warnings import check_warnings +from .exceptions import ValidationError, WarningError, MissingFolderError, MissingFileError diff --git a/fomod/validator/exceptions.py b/fomod/validator/exceptions.py new file mode 100644 index 0000000..a3880dc --- /dev/null +++ b/fomod/validator/exceptions.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + + +class MissingFolderError(Exception): + def __init__(self, folder): + self.msg = folder + " folder is missing." + Exception.__init__(self, self.msg) + + +class MissingFileError(Exception): + def __init__(self, file): + self.msg = file + " file is missing." + Exception.__init__(self, self.msg) + + +class ValidationError(Exception): + def __init__(self, msg=""): + self.msg = msg + Exception.__init__(self, self.msg) + + +class WarningError(Exception): + def __init__(self, msg=""): + self.msg = msg + Exception.__init__(self, self.msg) diff --git a/fomod/validator/utility.py b/fomod/validator/utility.py new file mode 100644 index 0000000..59b64c5 --- /dev/null +++ b/fomod/validator/utility.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + +from os import listdir +from .exceptions import MissingFileError, MissingFolderError + + +def check_fomod(package_path): + existing_fomod = False + fomod_folder = "fomod" + + try: + for folder in listdir(package_path): + if folder.upper() == "FOMOD": + existing_fomod = True + fomod_folder = folder + except FileNotFoundError: + raise MissingFolderError(fomod_folder) + + if not existing_fomod: + raise MissingFolderError(fomod_folder) + + return fomod_folder + + +def check_file(fomod_path): + config_exists = False + config_file = "moduleconfig.xml" + + for file in listdir(fomod_path): + if file.upper() == "MODULECONFIG.XML": + config_exists = True + config_file = file + + if not config_exists: + raise MissingFileError(config_file) + + return config_file diff --git a/fomod/validator/validate.py b/fomod/validator/validate.py new file mode 100644 index 0000000..074cd17 --- /dev/null +++ b/fomod/validator/validate.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + +from os.path import join +from lxml import etree +from .utility import check_fomod, check_file +from .exceptions import MissingFileError, MissingFolderError, ValidationError + + +def validate(package_path, cur_folder): + try: + fomod_folder = check_fomod(package_path) + config_file = check_file(join(package_path, fomod_folder)) + xmlschema_doc = etree.parse(join(cur_folder, "resources", "mod_schema.xsd")) + xmlschema = etree.XMLSchema(xmlschema_doc) + xmlschema.assertValid(etree.parse(join(package_path, fomod_folder, config_file))) + except (MissingFolderError, MissingFileError): + raise + except etree.DocumentInvalid as e: + raise ValidationError(check_file(join(package_path, check_fomod(package_path))) + + " is invalid with error message:\n\n" + str(e)) diff --git a/fomod/validator/warnings.py b/fomod/validator/warnings.py new file mode 100644 index 0000000..f02aec0 --- /dev/null +++ b/fomod/validator/warnings.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python + +# Copyright 2016 Daniel Nunes +# +# 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. + +from os.path import join, isfile, isdir +from lxml import etree +from .utility import check_file, check_fomod +from .exceptions import MissingFileError, MissingFolderError, WarningError + + +def check_warnings(package_path): + class ElementLog(object): + def __init__(self, elements, title, msg): + self.elements = {} + for elem_ in elements: + if elem_.tag not in self.elements.keys(): + self.elements[elem_.tag] = [elem_] + else: + self.elements[elem_.tag].append(elem_) + + self.title = title + + self.msgs = {} + for elem_ in elements: + self.msgs[elem_.tag] = msg.replace("{}", elem_.tag) + + result = "Warnings Log



" + result_initial = result + + repeatable_tags = ("moduleName", "moduleImage", "moduleDependencies", + "requiredInstallFiles", "installSteps", "conditionalFileInstalls", "") + repeated_elems = [] + repeated_elems_msg = "The tag {} has several occurrences, this may produce unexpected results." + folder_tags = ("folder",) + missing_folders = [] + missing_folders_msg = "These source folder(s) weren't found inside the package. " \ + "The installers ignore this so be sure to fix it." + file_tags = ("file",) + missing_files = [] + missing_files_msg = "These source file(s) weren't found inside the package. " \ + "The installers ignore this so be sure to fix it." + + try: + fomod_folder = check_fomod(package_path) + config_file = check_file(join(package_path, fomod_folder)) + config_tree = etree.parse(join(package_path, fomod_folder, config_file)) + + for element in config_tree.getroot().iter(): + if element.tag in repeatable_tags: + list_ = repeated_elems + elif element.tag in folder_tags: + list_ = missing_folders + elif element.tag in file_tags: + list_ = missing_files + else: + continue + + list_.append(element) + + result_repeat = [] + result_folder = [] + result_file = [] + + for elem in repeated_elems: + if sum(1 for value in repeated_elems if value.tag == elem.tag) >= 2: + result_repeat.append(elem) + + for elem in missing_folders: + if not isdir(join(package_path, elem.get("source"))): + result_folder.append(elem) + + for elem in missing_files: + if not isfile(join(package_path, elem.get("source"))): + result_file.append(elem) + + repeat_log = None + folder_log = None + file_log = None + + if result_repeat: + repeat_log = ElementLog(result_repeat, "Repeated Elements", repeated_elems_msg) + if result_folder: + folder_log = ElementLog(result_folder, "Missing Source Folders", missing_folders_msg) + if result_file: + file_log = ElementLog(result_file, "Missing Source Files", missing_files_msg) + + result += _log_warnings([repeat_log, folder_log, file_log]) + + if result != result_initial: + raise WarningError(result) + except (MissingFolderError, MissingFileError): + raise + + +def _log_warnings(list_): + result = "" + + for log in list_: + if log: + result += "" + log.title + "

" + + for tag in log.elements: + result += "Lines" + for elem in log.elements[tag]: + result += " " + str(elem.sourceline) + "," + result = result[:-1] + result += ": " + log.msgs[tag] + "
" + + result += "

" + + return result diff --git a/resources/mainframe.ui b/resources/mainframe.ui new file mode 100644 index 0000000..9c53cb7 --- /dev/null +++ b/resources/mainframe.ui @@ -0,0 +1,147 @@ + + + Dialog + + + + 0 + 0 + 566 + 151 + + + + + 0 + 0 + + + + + 436 + 151 + + + + + 566 + 151 + + + + FOMOD Validator + + + + + + + + + 0 + 0 + + + + true + + + Path to package... + + + false + + + + + + + + 0 + 0 + + + + ... + + + false + + + false + + + + + + + + + Validate FOMOD files. + + + true + + + + + + + Include warnings (non-existing files, invalid paths, tag recommendations). + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + true + + + + + + + + + buttonBox + accepted() + Dialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + Dialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/resources/mod_schema.xsd b/resources/mod_schema.xsd new file mode 100644 index 0000000..9c546aa --- /dev/null +++ b/resources/mod_schema.xsd @@ -0,0 +1,687 @@ + + + + + The main element containing the module configuration info. + + + + + + Describes the configuration of a module. + + + + + The name of the module. + + + + + The module logo. [Ignored in Mod Organizer] + + + + + Items upon which the module depends. + + + + + The list of files and folders that must be installed for this module. + + + + + The list of install steps that determine which files (or plugins) that may optionally be installed for this module. + + + + + The list of optional files that may optionally be installed for this module, base on condition flags. + + + + + + + + Describes the display properties of the module title. + + + + + + The identifying name of the condition flag. [Ignored in Mod Organizer] + + + + The possible title positions. + + + + + Positions the title on the left side of the form header. + + + + + Positions the title on the right side of the form header. + + + + + Positions the title on the right side of the image in the form header. + + + + + + + + The colour to use for the title. [Ignored in Mod Organizer] + + + + + + + + + An image. + + + + The path to the image in the FOMod. If omitted the FOMod's screenshot is used. + + + + + Whether or not the image should be displayed. + + + + + Whether or not the fade effect should be displayed. This value is ignored if showImage is false. + + + + + The height to use for the image. Note that there is a minimum height that is enforced based on the user's settings. + + + + + + + A dependency that is made up of one or more dependencies. + + + + + The relation of the contained dependencies. + + + + + + Indicates all contained dependencies must be satisfied in order for this dependency to be satisfied. + + + + + Indicates at least one listed dependency must be satisfied in order for this dependency to be satisfied. + + + + + + + + + + The group of possible dependencies. + + + + + + Specifies that a mod must be in a specified state. + + + + + Specifies that a condition flag must have a specific value. + + + + + Specifies a minimum required version of the installed game. [Ignored in Mod Organizer] + + + + + A list of mods and their states against which to match the user's installation. + + + + + + + + + A mod upon which the type of a plugin depends. + + + + The file of the mod upon which a the plugin depends. + + + + + The state of the mod file. + + + + + + Indicates the mod file is not installed. + + + + + Indicates the mod file is installed, but not active. + + + + + Indicates the mod file is installed and active. + + + + + + + + + + A condition flag upon which the type of a plugin depends. + + + + The name of the condition flag upon which a the plugin depends. + + + + + The value of the condition flag upon which a the plugin depends. + + + + + + + A required minimum version of an item. + + + + The required minimum version of the item. + + + + + + + A list of files and folders. + + + + + + A file belonging to the plugin or module. + + + + + A folder belonging to the plugin or module. + + + + + + + + + A file or folder that may be installed as part of a module or plugin. + + + + The path to the file or folder in the FOMod. + + + + + The path to which the file or folder should be installed. If omitted, the destination is the same as the source. + + + + + Indicates that the file or folder should always be installed, regardless of whether or not the plugin has been selected. [Ignored in Mod Organizer] + + + + + Indicates that the file or folder should always be installed if the plugin is not NotUsable, regardless of whether or not the plugin has been selected. [Ignored in Mod Organizer] + + + + + A number describing the relative priority of the file or folder. A higher number indicates the file or folder should be installed after the items with lower numbers. This value does not have to be unique. + + + + + + + A list of install steps. + + + + + A list of install steps for the mod. + + + + + + The order by which to list the steps. + + + + + + + A step in the install process containing groups of optional plugins. + + + + + The pattern against which to match the conditional flags and installed files. If the pattern is matched, then the install step will be visible. + + + + + The list of optional files (or plugins) that may optionally be installed for this module. + + + + + + The name of the install step. + + + + + + + A list of plugin groups. + + + + + A group of plugins for the mod. + + + + + + The order by which to list the groups. + + + + + + + A group of plugins. + + + + + The list of plugins in the group. + + + + + + The name of the group. + + + + + The type of the group. + + + + + + At least one plugin in the group must be selected. + + + + + At most one plugin in the group must be selected. + + + + + Exactly one plugin in the group must be selected. + + + + + All plugins in the group must be selected. + + + + + Any number of plugins in the group may be selected. + + + + + + + + + + A list of plugins. + + + + + A mod plugin belonging to a group. + + + + + + The order by which to list the plugins. + + + + + + + A plugin. + + + + + A description of the plugin. + + + + + The optional image associated with a plugin. + + + + + + + The list of files and folders that need to be installed for the plugin. + + + + + The list of condition flags to set if the plugin is in the appropriate state. + + + + + + + The list of condition flags to set if the plugin is in the appropriate state. + + + + + The list of files and folders that need to be installed for the plugin. + + + + + + + Describes the type of the plugin. + + + + + + The name of the plugin. + + + + + + + An image. + + + + The path to the image in the FOMod. + + + + + + + A list of condition flags to set if a plugin is in the appropriate state. + + + + + A condition flag to set if the plugin is selected. + + + + + + + + A condition flag to set if a plugin is selected. + + + + + + The identifying name of the condition flag. + + + + + + + + + Describes the type of a plugin. + + + + + Used when the plugin type is dependent upon the state of other mods. + + + + + The type of the plugin. + + + + + + + + A plugin type that is dependent upon the state of other mods. + + + + + The default type of the plugin used if none of the specified dependency states are satisfied. + + + + + The list of dependency patterns against which to match the user's installation. The first pattern that matches the user's installation determines the type of the plugin. + + + + + + + + The type of a given plugin. + + + + The name of the plugin type. + + + + + + + The possible plugin types. + + + + + Indicates the plugin must be installed. + + + + + Indicates the plugin is optional. + + + + + Indicates the plugin is recommended for stability. + + + + + Indicates that using the plugin could result in instability (i.e., a prerequisite plugin is missing). + + + + + + Indicates that using the plugin could result in instability if loaded + with the currently active plugins (i.e., a prerequisite plugin is missing), + but that the prerequisite plugin is installed, just not activated. + + + + + + + + + A list of dependency patterns. + + + + + A specific pattern of mod files and condition flags against which to match the user's installation. + + + + + + + + A pattern of mod files and condition flags that determine the type of a plugin. + + + + + The list of mods and their states against which to match the user's installation. + + + + + The type of the plugin. + + + + + + + + The possible orders of items. + + + + + Indicates the items are to be ordered ascending alphabetically. + + + + + Indicates the items are to be ordered descending alphabetically. + + + + + Indicates the items are to be ordered as listed in the configuration file. + + + + + + + + A list of optional files that may optionally be installed for this module, base on condition flags. + + + + + The list of patterns against which to match the conditional flags and installed files. All matching patterns will have their files installed. + + + + + + + + A list of conditional install patterns. + + + + + A specific pattern of mod files and condition flags against which to match the user's installation. + + + + + + + + A pattern of mod files and conditional flags that determine whether to install specific files. + + + + + The list of mods and their states against which to match the user's installation. + + + + + The files and filders to install if the pattern is matched. + + + + + diff --git a/setup.cfg b/setup.cfg index 94e2312..2d333e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,7 +1,9 @@ [bumpversion] -current_version = 0.0.0 +current_version = 1.0.0 current_build = 0 +[bumpversion:file:setup.py] + [bdist_wheel] -universal = 1 +universal = 0 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7aecba7 --- /dev/null +++ b/setup.py @@ -0,0 +1,14 @@ +from setuptools import setup + +setup( + name='fomod-validator', + version='1.0.0', + packages=['validator'], + package_dir={'validator': 'fomod/validator'}, + url='https://github.com/GandaG/fomod-validator', + license='Apache 2.0', + author='Daniel Nunes', + author_email='gandaganza@gmail.com', + description='Validate your FOMOD installers.', + install_requires=['lxml'], +) diff --git a/tasks.py b/tasks.py index 3f864ed..2fa12d9 100644 --- a/tasks.py +++ b/tasks.py @@ -58,7 +58,7 @@ def build(): from fnmatch import fnmatch # set which files will be included within the archive. - included_files = ["LICENSE", "README.md"] + included_files = ["LICENSE", "README.md", "CHANGELOG.md"] archive_name = "validator" # the archive's name try: