Added persistent user data and installer generator for windows.

This commit is contained in:
Joey Payne 2015-05-16 10:01:37 -06:00
commit a6f8ab247c
5 changed files with 202 additions and 21 deletions

137
Web2Exe.nsi Normal file
View file

@ -0,0 +1,137 @@
; Script generated by the HM NIS Edit Script Wizard.
; HM NIS Edit Wizard helper defines
!define PRODUCT_NAME "Web2Executable"
!define PRODUCT_VERSION "0.2.4b"
!define PRODUCT_PUBLISHER "SimplyPixelated"
!define PRODUCT_WEB_SITE "http://www.simplypixelated.com"
!define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\${PRODUCT_NAME}.exe"
!define PRODUCT_UNINST_KEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\${PRODUCT_NAME}"
!define PRODUCT_UNINST_ROOT_KEY "HKLM"
!define PRODUCT_STARTMENU_REGVAL "NSIS:StartMenuDir"
SetCompressor lzma
; MUI 1.67 compatible ------
!include "MUI.nsh"
; MUI Settings
!define MUI_ABORTWARNING
!define MUI_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
!define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"
; Welcome page
!insertmacro MUI_PAGE_WELCOME
; License page
!insertmacro MUI_PAGE_LICENSE "license.rtf"
; Components page
!insertmacro MUI_PAGE_COMPONENTS
; Directory page
!insertmacro MUI_PAGE_DIRECTORY
; Start menu page
var ICONS_GROUP
!define MUI_STARTMENUPAGE_NODISABLE
!define MUI_STARTMENUPAGE_DEFAULTFOLDER "${PRODUCT_NAME}"
!define MUI_STARTMENUPAGE_REGISTRY_ROOT "${PRODUCT_UNINST_ROOT_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_KEY "${PRODUCT_UNINST_KEY}"
!define MUI_STARTMENUPAGE_REGISTRY_VALUENAME "${PRODUCT_STARTMENU_REGVAL}"
!insertmacro MUI_PAGE_STARTMENU Application $ICONS_GROUP
; Instfiles page
!insertmacro MUI_PAGE_INSTFILES
; Finish page
!insertmacro MUI_PAGE_FINISH
; Uninstaller pages
!insertmacro MUI_UNPAGE_INSTFILES
; Language files
!insertmacro MUI_LANGUAGE "English"
; Reserve files
!insertmacro MUI_RESERVEFILE_INSTALLOPTIONS
; MUI end ------
Name "${PRODUCT_NAME} ${PRODUCT_VERSION}"
OutFile "Web2Exe-Setup.exe"
RequestExecutionLevel admin ;Require admin rights on NT6+ (When UAC is turned on)
!include LogicLib.nsh
Function .onInit
UserInfo::GetAccountType
pop $0
${If} $0 != "admin" ;Require admin rights on NT4+
MessageBox mb_iconstop "Administrator rights required!"
SetErrorLevel 740 ;ERROR_ELEVATION_REQUIRED
Quit
${EndIf}
FunctionEnd
InstallDir "$PROGRAMFILES\${PRODUCT_NAME}"
InstallDirRegKey HKLM "${PRODUCT_DIR_REGKEY}" ""
ShowInstDetails show
ShowUnInstDetails show
Section "Web2Executable" SEC01
SectionIn RO
SetOutPath "$INSTDIR"
SetOverwrite try
File /r "Web2ExeWin\"
; Shortcuts
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
CreateDirectory "$SMPROGRAMS\$ICONS_GROUP"
CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe"
CreateShortCut "$DESKTOP\${PRODUCT_NAME}.lnk" "$INSTDIR\${PRODUCT_NAME}.exe"
!insertmacro MUI_STARTMENU_WRITE_END
SectionEnd
LangString DESC_SEC01 ${LANG_ENGLISH} "A tool to convert web applications to exe's."
!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN
!insertmacro MUI_DESCRIPTION_TEXT ${SEC01} $(DESC_SEC01)
!insertmacro MUI_FUNCTION_DESCRIPTION_END
Section -AdditionalIcons
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
WriteIniStr "$INSTDIR\${PRODUCT_NAME}.url" "InternetShortcut" "URL" "${PRODUCT_WEB_SITE}"
CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Website.lnk" "$INSTDIR\${PRODUCT_NAME}.url"
CreateShortCut "$SMPROGRAMS\$ICONS_GROUP\Uninstall.lnk" "$INSTDIR\uninst.exe"
!insertmacro MUI_STARTMENU_WRITE_END
SectionEnd
Section -Post
WriteUninstaller "$INSTDIR\uninst.exe"
WriteRegStr HKLM "${PRODUCT_DIR_REGKEY}" "" "$INSTDIR\${PRODUCT_NAME}.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayName" "$(^Name)"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "UninstallString" "$INSTDIR\uninst.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayIcon" "$INSTDIR\${PRODUCT_NAME}.exe"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "DisplayVersion" "${PRODUCT_VERSION}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "URLInfoAbout" "${PRODUCT_WEB_SITE}"
WriteRegStr ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}" "Publisher" "${PRODUCT_PUBLISHER}"
SectionEnd
Function un.onUninstSuccess
HideWindow
MessageBox MB_ICONINFORMATION|MB_OK "$(^Name) was successfully removed from your computer."
FunctionEnd
Function un.onInit
MessageBox MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2 "Are you sure you want to completely remove $(^Name) and all of its components?" IDYES +2
Abort
FunctionEnd
Section Uninstall
RMDir /r "$INSTDIR"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Uninstall.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\Website.lnk"
Delete "$DESKTOP\${PRODUCT_NAME}.lnk"
Delete "$SMPROGRAMS\${PRODUCT_NAME}\${PRODUCT_NAME}.lnk"
DeleteRegKey ${PRODUCT_UNINST_ROOT_KEY} "${PRODUCT_UNINST_KEY}"
DeleteRegKey HKLM "${PRODUCT_DIR_REGKEY}"
SetAutoClose true
SectionEnd

View file

@ -1,9 +1,12 @@
'''Command line module for web2exe.'''
__version__ = "v0.2.4b"
from utils import zip_files, join_files, log, get_temp_dir
from pycns import save_icns
from pepy.pe import PEFile
import argparse
import urllib2
import platform
import re
@ -23,6 +26,8 @@ import logging.handlers as lh
import plistlib
import codecs
from utils import get_data_path, get_data_file_path
from semantic_version import Version
from zipfile import ZipFile
@ -45,15 +50,13 @@ def get_file(path):
return independent_path
TEMP_DIR = get_temp_dir()
DEFAULT_DOWNLOAD_PATH = os.path.join(CWD,
'files',
'downloads').replace('\\',
'\\\\')
DEFAULT_DOWNLOAD_PATH = get_data_path('files/downloads')
logger = logging.getLogger('W2E logger')
LOG_FILENAME = os.path.join(CWD, 'files', 'error.log')
LOG_FILENAME = get_data_file_path('files/error.log')
if __name__ != '__main__':
logging.basicConfig(
filename=os.path.join(CWD, 'files', 'error.log'),
filename=LOG_FILENAME,
format=("%(levelname) -10s %(asctime)s %(module)s.py: "
"%(lineno)s %(funcName)s - %(message)s"),
level=logging.DEBUG
@ -80,7 +83,7 @@ except:
def get_base_url():
url = None
try:
url = codecs.open(os.path.join(CWD, 'files', 'base_url.txt'), encoding='utf-8').read().strip()
url = codecs.open(get_file('files', 'base_url.txt'), encoding='utf-8').read().strip()
except (OSError, IOError):
url = 'http://dl.node-webkit.org/v{}/'
return url
@ -283,8 +286,9 @@ class CommandBase(object):
def setup_nw_versions(self):
nw_version = self.get_setting('nw_version')
nw_version.values = []
try:
f = codecs.open(os.path.join(CWD, 'files', 'nw-versions.txt'), encoding='utf-8')
f = codecs.open(get_data_file_path('files/nw-versions.txt'), encoding='utf-8')
for line in f:
nw_version.values.append(line.strip())
f.close()
@ -296,7 +300,7 @@ class CommandBase(object):
return nw_version.values[:]
def get_settings(self):
config_file = os.path.join(CWD, 'files', 'settings.cfg')
config_file = get_file('files/settings.cfg')
contents = codecs.open(config_file, encoding='utf-8').read()
contents = contents.replace(u'{DEFAULT_DOWNLOAD_PATH}',
DEFAULT_DOWNLOAD_PATH)
@ -375,7 +379,7 @@ class CommandBase(object):
nw_version.values = versions
f = None
try:
f = codecs.open(os.path.join(CWD, 'files', 'nw-versions.txt'), 'w', encoding='utf-8')
f = codecs.open(get_data_file_path('files/nw-versions.txt'), 'w', encoding='utf-8')
for v in nw_version.values:
f.write(v+os.linesep)
f.close()
@ -939,10 +943,16 @@ class CommandBase(object):
os.remove(f_path)
class ArgParser(argparse.ArgumentParser):
def error(self, message):
sys.stderr.write('error: {}\n'.format(message))
self.print_help()
sys.exit(2)
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description=('Command line interface '
'to web2exe'),
parser = ArgParser(description=('Command line interface '
'to web2exe. {}'.format(__version__)),
prog='web2execmd')
command_base = CommandBase()
command_base.init()
@ -965,6 +975,7 @@ if __name__ == '__main__':
help=('Loads the package.json '
'file in the project directory. '
'Ignores other command line arguments.'))
parser.add_argument('--cmd-version', action='version', version='%(prog)s {}'.format(__version__))
for setting_group_dict in command_base.settings['setting_groups']:
for setting_name, setting in setting_group_dict.items():
@ -1014,7 +1025,7 @@ if __name__ == '__main__':
)
else:
logging.basicConfig(
filename=os.path.join(CWD, 'files', 'error.log'),
filename=LOG_FILENAME,
format=("%(levelname) -10s %(asctime)s %(module)s.py: "
"%(lineno)s %(funcName)s - %(message)s"),
level=logging.DEBUG

18
license.rtf Normal file
View file

@ -0,0 +1,18 @@
{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210
{\fonttbl\f0\fnil\fcharset0 Verdana;}
{\colortbl;\red255\green255\blue255;\red57\green57\blue57;\red255\green255\blue255;}
\margl1440\margr1440\vieww10800\viewh8400\viewkind0
\deftab720
\pard\pardeftab720\sl400\sa291\qc
\f0\b\fs28 \cf2 \cb3 The MIT License (MIT)
\b0\fs24 \
\pard\pardeftab720\sl400\sa291
\b \cf2 Copyright (c)
\b0 2015 SimplyPixelated\
\pard\pardeftab720\sl400\sa291
\cf2 Permission is hereby granted, free of charge, to any person obtaining a copy\uc0\u8232 of this software and associated documentation files (the "Software"), to deal\u8232 in the Software without restriction, including without limitation the rights\u8232 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\u8232 copies of the Software, and to permit persons to whom the Software is\u8232 furnished to do so, subject to the following conditions:\
The above copyright notice and this permission notice shall be included in\uc0\u8232 all copies or substantial portions of the Software.\
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\
}

15
main.py
View file

@ -1,7 +1,5 @@
from utils import log, open_folder_in_explorer
__gui_version__ = "v0.2.3b"
import os
import re
import glob
@ -16,6 +14,9 @@ from PySide.QtCore import QUrl, QFile, QIODevice, QCoreApplication
from pycns import pngs_from_icns
from command_line import CommandBase, logger, get_file
from command_line import __version__ as __gui_version__
from utils import get_data_path, get_data_file_path
MAX_RECENT = 10
@ -56,7 +57,7 @@ class MainWindow(QtGui.QMainWindow, CommandBase):
def load_recent_projects(self):
files = []
history_file = get_file('files/recent_files.txt')
history_file = get_data_file_path('files/recent_files.txt')
if not os.path.exists(history_file):
return files
with codecs.open(history_file, encoding='utf-8') as f:
@ -69,7 +70,7 @@ class MainWindow(QtGui.QMainWindow, CommandBase):
def load_last_project_path(self):
proj_path = ''
proj_file = get_file('files/last_project_path.txt')
proj_file = get_data_file_path('files/last_project_path.txt')
if os.path.exists(proj_file):
with codecs.open(proj_file, encoding='utf-8') as f:
proj_path = f.read().strip()
@ -80,12 +81,12 @@ class MainWindow(QtGui.QMainWindow, CommandBase):
return proj_path
def save_project_path(self, path):
proj_file = get_file('files/last_project_path.txt')
proj_file = get_data_file_path('files/last_project_path.txt')
with codecs.open(proj_file, 'w+', encoding='utf-8') as f:
f.write(path)
def save_recent_project(self, proj):
recent_file_path = get_file('files/recent_files.txt')
recent_file_path = get_data_file_path('files/recent_files.txt')
max_length = MAX_RECENT
recent_files = []
if os.path.exists(recent_file_path):
@ -427,7 +428,7 @@ class MainWindow(QtGui.QMainWindow, CommandBase):
open_export_button = QtGui.QPushButton()
open_export_button.setEnabled(False)
open_export_button.setIcon(QtGui.QIcon(os.path.join('files', 'images', 'folder_open.png')))
open_export_button.setIcon(QtGui.QIcon(get_file('files/images/folder_open.png')))
open_export_button.setToolTip('Open Export Folder')
open_export_button.setStatusTip('Open Export Folder')
open_export_button.setMaximumWidth(30)

View file

@ -2,6 +2,7 @@ from __future__ import print_function
import os, zipfile, io, platform
import sys, tempfile
import subprocess
from appdirs import AppDirs
#try:
# import zlib
@ -17,6 +18,19 @@ def is_windows():
def get_temp_dir():
return tempfile.gettempdir()
def get_data_path(dir_path):
parts = dir_path.split('/')
dirs = AppDirs('Web2Executable', 'Web2Executable')
data_path = os.path.join(dirs.user_data_dir, *parts)
if not os.path.exists(data_path):
os.makedirs(data_path)
return data_path
def get_data_file_path(file_path):
parts = file_path.split('/')
data_path = get_data_path('/'.join(parts[:-1]))
return os.path.join(data_path, parts[-1])
def log(*args):
if DEBUG:
print(*args)