Electrify/main.py
2014-03-31 21:50:18 -06:00

846 lines
32 KiB
Python

from utils import zip_files, join_files
import sys, os, glob, json, re, shutil, stat, tarfile, zipfile, traceback, platform
from PySide import QtGui, QtCore
from PySide.QtGui import QApplication
from PySide.QtNetwork import QHttp
from PySide.QtCore import QUrl, QFileInfo, QFile, QIODevice
from zipfile import ZipFile
from tarfile import TarFile
#if this is a mac application
frozen = getattr(sys, 'frozen', '')
if frozen:
CWD = os.path.dirname(sys.executable)
os.chdir(CWD)
else:
CWD = os.getcwd()
if platform.system() == 'Windows':
TEMP_DIR = os.path.join('c:/','windows','temp')
else:
TEMP_DIR = os.path.sep+'tmp'
class WThread(QtCore.QThread):
def __init__(self, widget, method_name, parent=None):
QtCore.QThread.__init__(self, parent)
self.widget=widget
self.method_name = method_name
def run(self):
if hasattr(self.widget, self.method_name):
func = getattr(self.widget, self.method_name)
func()
class Setting(object):
def __init__(self, name='', display_name=None, value=None, required=False, type=None, file_types=None, *args, **kwargs):
self.name = name
self.display_name = display_name if display_name else name.replace('_',' ').capitalize()
self.value = value
self.required = required
self.type = type
self.file_types = file_types
for k, v in kwargs.items():
setattr(self, k, v)
self.default_value = kwargs.pop('default_value', None)
if self.value is None:
self.value = self.default_value
self.save_path = kwargs.pop('save_path', TEMP_DIR)
if hasattr(self, 'url'):
self.file_name = self.url.split('/')[-1]
self.full_file_path = os.path.join(self.save_path, self.file_name)
self.file_ext = os.path.splitext(self.file_name)[1]
if self.file_ext == '.zip':
self.extract_class = ZipFile
self.extract_args = ()
elif self.file_ext == '.gz':
self.extract_class = TarFile.open
self.extract_args = ('r:gz',)
def get_file_bytes(self):
fbytes = None
file = self.extract_class(self.full_file_path, *self.extract_args)
if self.file_ext == '.gz':
fbytes = file.extractfile(self.extract_file).read()
elif self.file_ext == '.zip':
fbytes = file.read(self.extract_file)
return fbytes
def __repr__(self):
return 'Setting: (name={}, display_name={}, value={}, required={}, type={})'.format(self.name, self.display_name, self.value, self.required, self.type)
class MainWindow(QtGui.QWidget):
base_url = 'http://node-webkit.s3-website-us-east-1.amazonaws.com/v0.9.2/'
app_settings = {'main': Setting(name='main', display_name='Main file', required=True, type='file', file_types='*.html *.php *.htm'),
'name': Setting(name='name', display_name='App Name', required=True, type='string'),
'description': Setting(name='description', default_default_value='', type='string'),
'version': Setting(name='version', default_value='0.1.0', type='string'),
'keywords':Setting(name='keywords', default_value='', type='string'),
'nodejs': Setting('nodejs', 'Include Nodejs', default_value=True, type='check'),
'node-main': Setting('node-main', 'Custom Nodejs Path', default_value='', type='file', file_types='*.js'),
'single-instance': Setting('single-instance', 'Single Instance', default_value=True, type='check')}
webkit_settings = {'plugin': Setting('plugin', 'Load plugins', default_value=False, type='check'),
'java': Setting('java', 'Load Java', default_value=False, type='check'),
'page-cache': Setting('page-cache', 'Enable Page Cache', default_value=False, type='check')}
window_settings = {'title': Setting(name='title', default_value='', type='string'),
'icon': Setting('icon', 'Window Icon', default_value='', type='file', file_types='*.png *.jpg *.jpeg'),
'width': Setting('width', default_value=640, type='string'),
'height': Setting('height', default_value=480, type='string'),
'min_width': Setting('min_width', default_value=None, type='string'),
'min_height': Setting('min_height', default_value=None, type='string'),
'max_width': Setting('max_width', default_value=None, type='string'),
'max_height': Setting('max_height', default_value=None, type='string'),
'toolbar': Setting('toolbar', 'Show Toolbar', default_value=False, type='check'),
'always-on-top': Setting('always-on-top', 'Always on top', default_value=False, type='check'),
'frame': Setting('frame', 'Show Window Frame', default_value=True, type='check'),
'show_in_taskbar': Setting('show_in_taskbar', 'Show In Taskbar', default_value=True, type='check'),
'visible': Setting('visible', default_value=True, type='check'),
'resizable': Setting('resizable', default_value=False, type='check'),
'fullscreen': Setting('fullscreen', default_value=False, type='check')}
export_settings = {'windows': Setting('windows', default_value=False, type='check',
url=base_url+'node-webkit-v0.9.2-win-ia32.zip',
extract_file='nw.exe',
dest_file='nw.exe'),
'mac': Setting('mac', default_value=False, type='check',
url=base_url+'node-webkit-v0.9.2-osx-ia32.zip',
extract_file=os.path.join('node-webkit.app','Contents',
'Frameworks','node-webkit Framework.framework',
'node-webkit Framework'),
dest_file=os.path.join('node-webkit.app','Contents',
'Frameworks','node-webkit Framework.framework',
'node-webkit Framework')),
'linux-x64': Setting('linux-x64', default_value=False, type='check',
url=base_url+'node-webkit-v0.9.2-linux-x64.tar.gz',
extract_file=os.path.join('node-webkit-v0.9.2-linux-x64','nw'),
dest_file='nw'),
'linux-x32': Setting('linux-x32', default_value=False, type='check',
url=base_url+'node-webkit-v0.9.2-linux-ia32.tar.gz',
extract_file=os.path.join('node-webkit-v0.9.2-linux-ia32','nw'),
dest_file='nw')}
_setting_groups = [app_settings, webkit_settings, window_settings, export_settings]
application_setting_order = ['main', 'node-main', 'name', 'description', 'version', 'keywords',
'nodejs', 'single-instance', 'plugin',
'java', 'page-cache']
window_setting_order = ['title', 'icon', 'width', 'height', 'min_width', 'min_height',
'max_width', 'max_height', 'toolbar', 'always-on-top', 'frame',
'show_in_taskbar', 'visible', 'resizable', 'fullscreen']
export_setting_order = ['windows', 'linux-x64', 'mac', 'linux-x32']
def __init__(self, width, height, parent=None):
super(MainWindow, self).__init__(parent)
self.httpGetId = 0
self.httpRequestAborted = False
self.thread = None
self.resize(width,height)
self.extract_error = None
layout = QtGui.QVBoxLayout()
dl_bar = self.createDownloadBar()
self.app_settings_widget = self.createApplicationSettings()
self.win_settings_widget = self.createWindowSettings()
self.ex_settings_widget = self.createExportSettings()
self.app_settings_widget.setEnabled(False)
self.win_settings_widget.setEnabled(False)
self.ex_settings_widget.setEnabled(False)
layout.addWidget(self.createDirectoryChoose())
layout.addWidget(self.app_settings_widget)
layout.addWidget(self.win_settings_widget)
layout.addWidget(self.ex_settings_widget)
layout.addLayout(dl_bar)
self.setLayout(layout)
self.setWindowTitle("Web2Executable")
def export(self, export_button, cancel_button):
self.files_to_download = []
for setting_name, setting in self.export_settings.items():
if setting.value == True:
self.files_to_download.append(setting)
if self.files_to_download:
self.progress_bar.setVisible(True)
cancel_button.setEnabled(True)
self.disableUIWhileWorking()
setting = self.files_to_download.pop()
try:
self.downloadFile(setting.url, setting)
except Exception as e:
if os.path.exists(setting.full_file_path):
os.remove(setting.full_file_path)
QtGui.QMessageBox.information(self, 'Error!', str(e))
else:
QtGui.QMessageBox.information(self, 'Export Options Empty!', 'Please choose one of the export options!')
def disableUIWhileWorking(self):
self.ex_button.setEnabled(False)
self.app_settings_widget.setEnabled(False)
self.win_settings_widget.setEnabled(False)
self.ex_settings_widget.setEnabled(False)
def enableUI(self):
self.ex_button.setEnabled(True)
self.app_settings_widget.setEnabled(True)
self.win_settings_widget.setEnabled(True)
self.ex_settings_widget.setEnabled(True)
def requiredSettingsFilled(self):
proj_dir = self.projectDir()
out_dir = self.outputDir()
valid_proj_dir = False
if proj_dir and out_dir:
if os.path.exists(proj_dir):
valid_proj_dirs = True
settings_valid = True
for sgroup in self._setting_groups:
for sname, setting in sgroup.items():
if setting.required and not setting.value:
return False
if setting.type == 'file' and setting.value and not os.path.exists(os.path.join(self.projectDir(),setting.value)):
print setting.value, "does not exist"
settings_valid = False
export_chosen = False
for setting_name, setting in self.export_settings.items():
if setting.value:
export_chosen = True
return export_chosen and valid_proj_dirs and settings_valid
def projectDir(self):
if hasattr(self, 'input_line'):
return self.input_line.text()
return ''
def outputDir(self):
if hasattr(self, 'output_line'):
return self.output_line.text()
return ''
def createDownloadBar(self):
hlayout = QtGui.QHBoxLayout()
vlayout = QtGui.QVBoxLayout()
progress_label = QtGui.QLabel('')
progress_bar = QtGui.QProgressBar()
progress_bar.setVisible(False)
vlayout.addWidget(progress_label)
vlayout.addWidget(progress_bar)
vlayout.addWidget(QtGui.QLabel(''))
ex_button = QtGui.QPushButton('Export')
ex_button.setEnabled(False)
cancel_button = QtGui.QPushButton('Cancel Download')
cancel_button.setEnabled(False)
ex_button.clicked.connect(self.callWithObject('export', ex_button, cancel_button))
cancel_button.clicked.connect(self.cancelDownload)
buttonBox = QtGui.QDialogButtonBox()
buttonBox.addButton(cancel_button, QtGui.QDialogButtonBox.RejectRole)
buttonBox.addButton(ex_button, QtGui.QDialogButtonBox.AcceptRole)
hlayout.addLayout(vlayout)
hlayout.addWidget(buttonBox)
self.progress_label = progress_label
self.progress_bar = progress_bar
self.cancel_button = cancel_button
http = QHttp(self)
http.requestFinished.connect(self.httpRequestFinished)
http.dataReadProgress.connect(self.updateProgressBar)
http.responseHeaderReceived.connect(self.readResponseHeader)
self.http = http
self.cancel_button = cancel_button
self.ex_button = ex_button
return hlayout
def readResponseHeader(self, response_header):
# Check for genuine error conditions.
if response_header.statusCode() not in (200, 300, 301, 302, 303, 307):
QtGui.QMessageBox.information(self, 'Error',
'Download failed: %s.' % response_header.reasonPhrase())
self.httpRequestAborted = True
self.http.abort()
def httpRequestFinished(self, requestId, error):
if requestId != self.httpGetId:
return
if self.httpRequestAborted:
if self.outFile is not None:
self.outFile.close()
self.outFile.remove()
self.outFile = None
return
self.outFile.close()
if error:
self.outFile.remove()
QtGui.QMessageBox.information(self, 'Error',
'Download failed: %s.' % self.http.errorString())
self.continueDownloadingOrExtract()
def continueDownloadingOrExtract(self):
if self.files_to_download:
setting = self.files_to_download.pop()
self.downloadFile(setting.url, setting)
else:
self.progress_label.setText('Done')
self.cancel_button.setEnabled(False)
self.progress_bar.setVisible(False)
self.enableUI()
self.extractFilesInBackground()
def runInBackground(self, method_name, callback):
self.thread = WThread(self, method_name)
self.thread.finished.connect(callback)
self.thread.start()
def makeOutputFilesInBackground(self):
self.ex_button.setEnabled(False)
self.runInBackground('makeOutputDirs', self.doneMakingFiles)
def doneMakingFiles(self):
self.ex_button.setEnabled(True)
self.progress_label.setText('Done Exporting.')
if self.output_err:
QtGui.QMessageBox.information(self, 'Error!', str(self.output_err))
def extractFilesInBackground(self):
self.progress_label.setText('Extracting')
self.ex_button.setEnabled(False)
self.runInBackground('extractFiles', self.doneExtracting)
def extractFiles(self):
self.extract_error = None
for setting_name, setting in self.export_settings.items():
try:
if setting.value:
extract_path = os.path.join('files', setting.name)
if not os.path.exists(os.path.join(extract_path, setting.dest_file)):
fbytes = setting.get_file_bytes()
with open(os.path.join(extract_path, setting.dest_file), 'wb') as d:
d.write(fbytes)
if os.path.exists(setting.full_file_path):
os.remove(setting.full_file_path) #remove the zip/tar since we don't need it anymore
self.progress_label.setText(self.progress_label.text()+'.')
except (tarfile.ReadError, zipfile.BadZipfile) as e:
if os.path.exists(setting.full_file_path):
os.remove(setting.full_file_path)
self.extract_error = e
#cannot use GUI in thread to notify user. Save it for later
def doneExtracting(self):
self.ex_button.setEnabled(True)
self.enableUI()
if self.extract_error:
self.progress_label.setText('Error extracting.')
QtGui.QMessageBox.information(self, 'Error!', 'There were one or more errors with your zip/tar files. They were deleted. Please try to export again.')
else:
self.progress_label.setText('Done Extracting.')
self.makeOutputFilesInBackground()
def cancelDownload(self):
self.progress_label.setText("Download canceled.")
self.cancel_button.setEnabled(False)
self.httpRequestAborted = True
self.http.abort()
self.enableUI()
def updateProgressBar(self, bytesRead, totalBytes):
if self.httpRequestAborted:
return
self.progress_bar.setMaximum(totalBytes)
self.progress_bar.setValue(bytesRead)
def downloadFile(self, path, setting):
self.progress_label.setText('Downloading {}'.format(path.replace(self.base_url,'')))
url = QUrl(path)
fileInfo = QFileInfo(url.path())
fileName = setting.full_file_path
if QFile.exists(fileName) or QFile.exists(os.path.join('files', setting.name, setting.dest_file)):
self.continueDownloadingOrExtract()
return #QFile.remove(fileName)
self.outFile = QFile(fileName)
if not self.outFile.open(QIODevice.WriteOnly):
QtGui.QMessageBox.information(self, 'Error',
'Unable to save the file %s: %s.' % (fileName, self.outFile.errorString()))
self.outFile = None
self.enableUI()
return
mode = QHttp.ConnectionModeHttp
port = url.port()
if port == -1:
port = 0
self.http.setHost(url.host(), mode, port)
self.httpRequestAborted = False
path = QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:@/")
if path:
path = str(path)
else:
path = '/'
# Download the file.
self.httpGetId = self.http.get(path, self.outFile)
def createDirectoryChoose(self):
groupBox = QtGui.QGroupBox("Choose Your Web Project")
input_layout = QtGui.QHBoxLayout()
input_label = QtGui.QLabel('Project Directory:')
self.input_line = QtGui.QLineEdit()
self.input_line.textChanged.connect(self.projectPathChanged)
input_button = QtGui.QPushButton('...')
input_button.clicked.connect(self.browseDir)
input_layout.addWidget(input_label)
input_layout.addWidget(self.input_line)
input_layout.addWidget(input_button)
output_layout = QtGui.QHBoxLayout()
output_label = QtGui.QLabel('Output Directory:')
self.output_line = QtGui.QLineEdit()
self.output_line.textChanged.connect(self.projectPathChanged)
output_button = QtGui.QPushButton('...')
output_button.clicked.connect(self.browseOutDir)
output_layout.addWidget(output_label)
output_layout.addWidget(self.output_line)
output_layout.addWidget(output_button)
vlayout = QtGui.QVBoxLayout()
vlayout.addLayout(input_layout)
vlayout.addLayout(output_layout)
groupBox.setLayout(vlayout)
return groupBox
def callWithObject(self, name, obj, *args, **kwargs):
"""Allows arguments to be passed to click events"""
def call():
if hasattr(self, name):
func = getattr(self, name)
func(obj, *args, **kwargs)
return call
def findChildByName(self, name):
return self.findChild(QtCore.QObject, name)
def findAllChildren(self, names):
children = []
for child in self.findChildren(QtCore.QObject):
if child.objectName() in names:
children.append(child)
return children
def projectName(self):
return self.findChildByName('name').text()
def browseDir(self):
directory = QtGui.QFileDialog.getExistingDirectory(self, "Find Project Directory",
self.projectDir() or QtCore.QDir.currentPath())
if directory:
self.resetSettings()
self.input_line.setText(directory)
self.output_line.setText(os.path.join(directory,'output'))
proj_name = os.path.basename(directory)
setting_input = self.findChildByName('main')
files = glob.glob(os.path.join(directory,'index.html')) + glob.glob(os.path.join(directory,'index.php')) + glob.glob(os.path.join(directory,'index.htm'))
if not setting_input.text():
if files:
setting_input.setText(files[0])
app_name_input = self.findChildByName('name')
title_input = self.findChildByName('title')
if not app_name_input.text():
app_name_input.setText(proj_name)
if not title_input.text():
title_input.setText(proj_name)
self.loadPackageJson()
def browseOutDir(self):
directory = QtGui.QFileDialog.getExistingDirectory(self, "Choose Output Directory",
self.projectDir() or QtCore.QDir.currentPath())
if directory:
self.output_line.setText(directory)
def getFile(self, obj, text_obj, setting, *args, **kwargs):
file, junk = QtGui.QFileDialog.getOpenFileName(self, 'Choose File', self.projectDir() or QtCore.QDir.currentPath(), setting.file_types)
if file:
text_obj.setText(file)
def createApplicationSettings(self):
groupBox = QtGui.QGroupBox("Application Settings")
vlayout = self.createLayout(self.application_setting_order)
groupBox.setLayout(vlayout)
return groupBox
def createSetting(self, name):
setting = self.getSetting(name)
if setting.type == 'string':
return self.createTextInputSetting(name)
elif setting.type == 'file':
return self.createTextInputWithFileSetting(name)
elif setting.type == 'check':
return self.createCheckSetting(name)
def createWindowSettings(self):
groupBox = QtGui.QGroupBox("Window Settings")
vlayout = self.createLayout(self.window_setting_order)
groupBox.setLayout(vlayout)
return groupBox
def createExportSettings(self):
groupBox = QtGui.QGroupBox("Export to")
vlayout = self.createLayout(self.export_setting_order)
groupBox.setLayout(vlayout)
return groupBox
def createLayout(self, settings, cols=2):
hlayout = QtGui.QHBoxLayout()
layouts = []
for i in xrange(cols):
l = QtGui.QFormLayout()
l.setSpacing(10)
l.setVerticalSpacing(10)
layouts.append(l)
col = 0
row = 0
for setting_name in settings:
setting = self.getSetting(setting_name)
if col >= cols:
row += 1
col = 0
vlayout = layouts[col]
display_name = setting.display_name+':'
if setting.required:
display_name += '*'
vlayout.addRow(display_name, self.createSetting(setting_name))
col += 1
for l in layouts:
hlayout.addLayout(l)
hlayout.setSpacing(20)
return hlayout
def createTextInputSetting(self, name):
hlayout = QtGui.QHBoxLayout()
setting = self.getSetting(name)
text = QtGui.QLineEdit()
text.setObjectName(setting.name)
text.textChanged.connect(self.callWithObject('settingChanged', text, setting))
if setting.value:
text.setText(str(setting.value))
hlayout.addWidget(text)
return hlayout
def createTextInputWithFileSetting(self, name):
hlayout = QtGui.QHBoxLayout()
setting = self.getSetting(name)
text = QtGui.QLineEdit()
text.setObjectName(setting.name)
button = QtGui.QPushButton('...')
button.setMaximumWidth(30)
button.setMaximumHeight(26)
button.clicked.connect(self.callWithObject('getFile', button, text, setting))
if setting.value:
text.setText(str(setting.value))
text.textChanged.connect(self.callWithObject('settingChanged', text, setting))
hlayout.addWidget(text)
hlayout.addWidget(button)
return hlayout
def resetSettings(self):
for sgroup in self._setting_groups:
for setting in sgroup.values():
widget = self.findChildByName(setting.name)
if setting.type == 'string' or setting.type == 'file':
old_val = ''
if setting.default_value is not None:
old_val = setting.default_value
setting.value = old_val
widget.setText(str(old_val))
elif setting.type == 'check':
old_val = False
if setting.default_value is not None:
old_val = setting.default_value
setting.value = old_val
widget.setChecked(old_val)
def settingChanged(self, obj, setting, *args, **kwargs):
if setting.type == 'string' or setting.type == 'file':
setting.value = obj.text()
elif setting.type == 'check':
setting.value = obj.isChecked()
self.ex_button.setEnabled(self.requiredSettingsFilled())
def projectPathChanged(self):
self.ex_button.setEnabled(self.requiredSettingsFilled())
dirs_filled_out = False
if self.projectDir() and self.outputDir():
if os.path.exists(self.projectDir()):
dirs_filled_out = True
self.app_settings_widget.setEnabled(dirs_filled_out)
self.win_settings_widget.setEnabled(dirs_filled_out)
self.ex_settings_widget.setEnabled(dirs_filled_out)
def getSetting(self, name):
for setting_group in self._setting_groups:
if name in setting_group:
setting = setting_group[name]
return setting
def createCheckSetting(self, name):
hlayout = QtGui.QHBoxLayout()
setting = self.getSetting(name)
check = QtGui.QCheckBox()
check.setObjectName(setting.name)
check.clicked.connect(self.callWithObject('settingChanged', check, setting))
check.setChecked(setting.value)
hlayout.addWidget(check)
return hlayout
def generate_json(self):
dic = {'webkit':{},
'window':{}}
for setting_name, setting in self.app_settings.items():
if setting.value is not None:
dic[setting_name] = setting.value
if setting_name == 'keywords':
dic[setting_name] = re.findall("\w+", setting.value)
for setting_name, setting in self.window_settings.items():
if setting.value is not None:
if 'height' in setting.name or 'width' in setting.name:
try:
dic['window'][setting_name] = int(setting.value)
except ValueError:
pass
else:
dic['window'][setting_name] = setting.value
for setting_name, setting in self.webkit_settings.items():
if setting.value is not None:
dic['webkit'][setting_name] = setting.value
s = json.dumps(dic, indent=4)
return s
def loadPackageJson(self):
p_json = glob.glob(os.path.join(self.projectDir(), 'package.json'))
if p_json:
json_str = ''
with open(p_json[0], 'r') as f:
json_str = f.read()
try:
self.load_from_json(json_str)
except ValueError: #Json file is invalid
print 'Warning: Json file invalid.'
def load_from_json(self, json_str):
dic = json.loads(json_str)
stack = [dic]
while stack:
new_dic = stack.pop()
for item in new_dic:
setting_field = self.findChildByName(item)
setting = self.getSetting(item)
if setting_field:
if setting.type == 'file' or setting.type == 'string':
val_str = self.convert_val_to_str(new_dic[item])
setting_field.setText(val_str)
setting.value = val_str
if setting.type == 'check':
setting_field.setChecked(new_dic[item])
setting.value = new_dic[item]
if isinstance(new_dic[item], dict):
stack.append(new_dic[item])
def convert_val_to_str(self, val):
if isinstance(val, (list,tuple)):
return ', '.join(val)
return str(val)
def copyFilesToProjectFolder(self):
old_dir = CWD
os.chdir(self.projectDir())
for sgroup in self._setting_groups:
for setting in sgroup.values():
if setting.type == 'file' and setting.value:
try:
setting.value = os.path.basename(setting.value)
shutil.copy(setting.value, self.projectDir())
except shutil.Error as e:#same file warning
print 'Warning: {}'.format(e)
os.chdir(old_dir)
def makeOutputDirs(self):
self.output_err = ''
try:
self.progress_label.setText('Removing old output directory...')
outputDir = os.path.join(self.outputDir(), self.projectName())
tempDir = os.path.join(TEMP_DIR, 'webexectemp')
if os.path.exists(tempDir):
shutil.rmtree(tempDir)
self.progress_label.setText('Making new directories...')
if not os.path.exists(outputDir):
os.makedirs(outputDir)
os.makedirs(tempDir)
self.copyFilesToProjectFolder()
json_file = os.path.join(self.projectDir(), 'package.json')
with open(json_file, 'w+') as f:
f.write(self.generate_json())
zip_file = os.path.join(tempDir, self.projectName()+'.nw')
zip_files(zip_file, self.projectDir(), exclude_paths=[outputDir])
for ex_setting in self.export_settings.values():
if ex_setting.value:
self.progress_label.setText('Making files for {}'.format(ex_setting.display_name))
export_dest = os.path.join(outputDir, ex_setting.name)
if os.path.exists(export_dest):
shutil.rmtree(export_dest)
#shutil will make the directory for us
shutil.copytree(os.path.join('files', ex_setting.name), export_dest)
self.progress_label.setText(self.progress_label.text()+'.')
if ex_setting.name == 'mac':
app_path = os.path.join(export_dest, self.projectName()+'.app')
shutil.move(os.path.join(export_dest, 'node-webkit.app'), app_path)
self.progress_label.setText(self.progress_label.text()+'.')
shutil.move(zip_file, os.path.join(app_path, 'Contents', 'Resources', 'app.nw'))
self.progress_label.setText(self.progress_label.text()+'.')
else:
ext = ''
if ex_setting.name == 'windows':
ext = '.exe'
nw_path = os.path.join(export_dest, ex_setting.dest_file)
dest_binary_path = os.path.join(export_dest, self.projectName()+ext)
join_files(os.path.join(export_dest, self.projectName()+ext), nw_path, zip_file)
sevenfivefive = stat.S_IRWXU | stat.S_IRGRP | stat.S_IXGRP | stat.S_IROTH | stat.S_IXOTH
os.chmod(dest_binary_path, sevenfivefive)
self.progress_label.setText(self.progress_label.text()+'.')
if os.path.exists(nw_path):
os.remove(nw_path)
except Exception as e:
self.output_err += ''.join(traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]))
finally:
shutil.rmtree(tempDir)
def show_and_raise(self):
self.show()
self.raise_()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = MainWindow(700, 500)
frame.show_and_raise()
sys.exit(app.exec_())