Skip to content

Commit

Permalink
Merge branch 'release/v1.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniel Nunes committed Apr 21, 2016
2 parents bde9418 + 33955ef commit 8127bb1
Show file tree
Hide file tree
Showing 19 changed files with 1,315 additions and 8 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

Changelog
=========

1.0.0 (2016-04-21)

* Initial stable release.
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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]
Expand Down
21 changes: 21 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -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
13 changes: 13 additions & 0 deletions dev/appveyor-bootstrap.bat
Original file line number Diff line number Diff line change
@@ -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
3 changes: 2 additions & 1 deletion dev/pyinstaller-build.spec
Original file line number Diff line number Diff line change
Expand Up @@ -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=[],
Expand Down
4 changes: 4 additions & 0 deletions dev/reqs.txt
Original file line number Diff line number Diff line change
@@ -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
9 changes: 8 additions & 1 deletion fomod/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
49 changes: 49 additions & 0 deletions fomod/exceptions.py
Original file line number Diff line number Diff line change
@@ -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 <a href = https://github.com/GandaG/fomod-validator/issues>Github</a>,"
" or <a href = http://forum.step-project.com/index.php>STEP</a>.")
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_()
85 changes: 85 additions & 0 deletions fomod/mainframe.py
Original file line number Diff line number Diff line change
@@ -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("~")))
19 changes: 19 additions & 0 deletions fomod/validator/__init__.py
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions fomod/validator/exceptions.py
Original file line number Diff line number Diff line change
@@ -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)
51 changes: 51 additions & 0 deletions fomod/validator/utility.py
Original file line number Diff line number Diff line change
@@ -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
34 changes: 34 additions & 0 deletions fomod/validator/validate.py
Original file line number Diff line number Diff line change
@@ -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))
Loading

0 comments on commit 8127bb1

Please sign in to comment.