Added command-line utility. Refactored code to accomodate.
This commit is contained in:
parent
8d3397f8b1
commit
f7fa4cb6b6
9 changed files with 1261 additions and 865 deletions
741
command_line.py
Normal file
741
command_line.py
Normal file
|
|
@ -0,0 +1,741 @@
|
||||||
|
'''Command line module for web2exe.'''
|
||||||
|
|
||||||
|
from utils import zip_files, join_files, log, get_temp_dir
|
||||||
|
from pycns import save_icns
|
||||||
|
from pepy.pe import PEFile
|
||||||
|
|
||||||
|
import urllib2
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import shutil
|
||||||
|
import stat
|
||||||
|
import tarfile
|
||||||
|
import zipfile
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from distutils.version import LooseVersion
|
||||||
|
|
||||||
|
from zipfile import ZipFile
|
||||||
|
from tarfile import TarFile
|
||||||
|
|
||||||
|
try:
|
||||||
|
from cStringIO import StringIO
|
||||||
|
except ImportError:
|
||||||
|
from StringIO import StringIO
|
||||||
|
|
||||||
|
from configobj import ConfigObj
|
||||||
|
|
||||||
|
inside_mac_app = getattr(sys, 'frozen', '')
|
||||||
|
|
||||||
|
if inside_mac_app:
|
||||||
|
CWD = os.path.dirname(sys.executable)
|
||||||
|
os.chdir(CWD)
|
||||||
|
else:
|
||||||
|
CWD = os.getcwd()
|
||||||
|
|
||||||
|
TEMP_DIR = get_temp_dir()
|
||||||
|
DEFAULT_DOWNLOAD_PATH = os.path.join(CWD, 'files', 'downloads')
|
||||||
|
try:
|
||||||
|
os.makedirs(DEFAULT_DOWNLOAD_PATH)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_base_url():
|
||||||
|
url = None
|
||||||
|
try:
|
||||||
|
url = open(os.path.join(CWD, 'files', 'base_url.txt')).read().strip()
|
||||||
|
except (OSError, IOError):
|
||||||
|
url = 'http://dl.node-webkit.org/v{}/'
|
||||||
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
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.last_value = None
|
||||||
|
self.required = required
|
||||||
|
self.type = type
|
||||||
|
self.file_types = file_types
|
||||||
|
|
||||||
|
self.default_value = kwargs.pop('default_value', None)
|
||||||
|
self.button = kwargs.pop('button', None)
|
||||||
|
self.button_callback = kwargs.pop('button_callback', None)
|
||||||
|
self.description = kwargs.pop('description', '')
|
||||||
|
self.values = kwargs.pop('values', [])
|
||||||
|
|
||||||
|
self.set_extra_attributes_from_keyword_args(kwargs)
|
||||||
|
|
||||||
|
if self.value is None:
|
||||||
|
self.value = self.default_value
|
||||||
|
|
||||||
|
self.save_path = kwargs.pop('save_path', '')
|
||||||
|
|
||||||
|
self.get_file_information_from_url()
|
||||||
|
|
||||||
|
def get_file_information_from_url(self):
|
||||||
|
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 save_file_path(self, version, location=None):
|
||||||
|
if location:
|
||||||
|
self.save_path = location
|
||||||
|
else:
|
||||||
|
self.save_path = self.save_path or DEFAULT_DOWNLOAD_PATH
|
||||||
|
self.get_file_information_from_url()
|
||||||
|
|
||||||
|
if self.full_file_path:
|
||||||
|
return self.full_file_path.format(version)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def extract_file_path(self, version):
|
||||||
|
if self.extract_file:
|
||||||
|
return self.extract_file.format(version)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
def set_extra_attributes_from_keyword_args(self, kwargs):
|
||||||
|
for undefined_key, undefined_value in kwargs.items():
|
||||||
|
setattr(self, undefined_key, undefined_value)
|
||||||
|
|
||||||
|
def get_file_bytes(self, version):
|
||||||
|
fbytes = []
|
||||||
|
|
||||||
|
file = self.extract_class(self.save_file_path(version),
|
||||||
|
*self.extract_args)
|
||||||
|
for extract_path, dest_path in zip(self.extract_files,
|
||||||
|
self.dest_files):
|
||||||
|
new_bytes = None
|
||||||
|
try:
|
||||||
|
extract_p = extract_path.format(version)
|
||||||
|
if self.file_ext == '.gz':
|
||||||
|
new_bytes = file.extractfile(extract_p).read()
|
||||||
|
elif self.file_ext == '.zip':
|
||||||
|
new_bytes = file.read(extract_p)
|
||||||
|
except KeyError as e:
|
||||||
|
log(e)
|
||||||
|
# dirty hack to support old versions of nw
|
||||||
|
if 'no item named' in str(e):
|
||||||
|
extract_path = '/'.join(extract_path.split('/')[1:])
|
||||||
|
try:
|
||||||
|
if self.file_ext == '.gz':
|
||||||
|
new_bytes = file.extractfile(extract_path).read()
|
||||||
|
elif self.file_ext == '.zip':
|
||||||
|
new_bytes = file.read(extract_path)
|
||||||
|
except KeyError as e:
|
||||||
|
log(e)
|
||||||
|
print e
|
||||||
|
print e
|
||||||
|
|
||||||
|
if new_bytes is not None:
|
||||||
|
fbytes.append((dest_path, new_bytes))
|
||||||
|
|
||||||
|
return fbytes
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
url = ''
|
||||||
|
if hasattr(self, 'url'):
|
||||||
|
url = self.url
|
||||||
|
return ('Setting: (name={}, '
|
||||||
|
'display_name={}, '
|
||||||
|
'value={}, required={}, '
|
||||||
|
'type={}, url={})').format(self.name,
|
||||||
|
self.display_name,
|
||||||
|
self.value,
|
||||||
|
self.required,
|
||||||
|
self.type,
|
||||||
|
url)
|
||||||
|
|
||||||
|
|
||||||
|
class CommandBase(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.quiet = False
|
||||||
|
self.output_package_json = False
|
||||||
|
self.settings = self.get_settings()
|
||||||
|
self._project_dir = ''
|
||||||
|
self._output_dir = ''
|
||||||
|
self._progress_text = ''
|
||||||
|
self._output_err = ''
|
||||||
|
self._extract_error = ''
|
||||||
|
self.original_packagejson = {}
|
||||||
|
|
||||||
|
def update_nw_versions(self):
|
||||||
|
self.get_versions()
|
||||||
|
|
||||||
|
def get_settings(self):
|
||||||
|
config_file = os.path.join(CWD, 'files', 'settings.cfg')
|
||||||
|
contents = open(config_file).read()
|
||||||
|
contents = contents.replace('{DEFAULT_DOWNLOAD_PATH}',
|
||||||
|
DEFAULT_DOWNLOAD_PATH)
|
||||||
|
config_io = StringIO(contents)
|
||||||
|
config = ConfigObj(config_io, unrepr=True)
|
||||||
|
settings = {'setting_groups': []}
|
||||||
|
setting_items = (config['setting_groups'].items() +
|
||||||
|
[('export_settings', config['export_settings'])])
|
||||||
|
for setting_group, setting_group_dict in setting_items:
|
||||||
|
settings[setting_group] = {}
|
||||||
|
for setting_name, setting_dict in setting_group_dict.items():
|
||||||
|
for key in setting_dict.keys():
|
||||||
|
if '_callback' in key:
|
||||||
|
setting_dict[key] = getattr(self, setting_dict[key])
|
||||||
|
for key, val in setting_dict.items():
|
||||||
|
setting_dict[key] = val
|
||||||
|
setting_obj = Setting(name=setting_name, **setting_dict)
|
||||||
|
settings[setting_group][setting_name] = setting_obj
|
||||||
|
|
||||||
|
sgroup_items = config['setting_groups'].items()
|
||||||
|
for setting_group, setting_group_dict in sgroup_items:
|
||||||
|
settings['setting_groups'].append(settings[setting_group])
|
||||||
|
|
||||||
|
config.pop('setting_groups')
|
||||||
|
config.pop('export_settings')
|
||||||
|
for key, val in config.items():
|
||||||
|
settings[key] = val
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
|
def project_dir(self):
|
||||||
|
return self._project_dir
|
||||||
|
|
||||||
|
def output_dir(self):
|
||||||
|
return self._output_dir
|
||||||
|
|
||||||
|
def project_name(self):
|
||||||
|
return os.path.basename(os.path.dirname(self.project_dir()))
|
||||||
|
|
||||||
|
def get_setting(self, name):
|
||||||
|
for setting_group in (self.settings['setting_groups'] +
|
||||||
|
[self.settings['export_settings']]):
|
||||||
|
if name in setting_group:
|
||||||
|
setting = setting_group[name]
|
||||||
|
return setting
|
||||||
|
|
||||||
|
def show_error(self, error):
|
||||||
|
print error
|
||||||
|
|
||||||
|
def enable_ui_after_error(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_versions(self):
|
||||||
|
response = urllib2.urlopen(self.settings['version_info']['url'])
|
||||||
|
html = response.read()
|
||||||
|
|
||||||
|
nw_version = self.get_setting('nw_version')
|
||||||
|
|
||||||
|
old_versions = set(nw_version.values)
|
||||||
|
new_versions = set(re.findall('(\S+) / \S+', html))
|
||||||
|
|
||||||
|
versions = sorted(list(old_versions.union(new_versions)),
|
||||||
|
key=LooseVersion, reverse=True)
|
||||||
|
nw_version.values = versions
|
||||||
|
f = None
|
||||||
|
try:
|
||||||
|
f = open(os.path.join(CWD, 'files', 'nw-versions.txt'), 'w')
|
||||||
|
for v in nw_version.values:
|
||||||
|
f.write(v+os.linesep)
|
||||||
|
except IOError:
|
||||||
|
error = ''.join(traceback.format_exception(sys.exc_info()[0],
|
||||||
|
sys.exc_info()[1],
|
||||||
|
sys.exc_info()[2]))
|
||||||
|
self.show_error(error)
|
||||||
|
self.enable_ui_after_error()
|
||||||
|
finally:
|
||||||
|
if f:
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
def download_file_with_error_handling(self):
|
||||||
|
setting = self.files_to_download.pop()
|
||||||
|
location = self.get_setting('download_dir').value
|
||||||
|
version = self.selected_version()
|
||||||
|
try:
|
||||||
|
return self.download_file(setting.url.format(version, version),
|
||||||
|
setting)
|
||||||
|
except (Exception, KeyboardInterrupt):
|
||||||
|
if os.path.exists(setting.save_file_path(version, location)):
|
||||||
|
os.remove(setting.save_file_path(version, location))
|
||||||
|
|
||||||
|
error = ''.join(traceback.format_exception(sys.exc_info()[0],
|
||||||
|
sys.exc_info()[1],
|
||||||
|
sys.exc_info()[2]))
|
||||||
|
self.show_error(error)
|
||||||
|
self.enable_ui_after_error()
|
||||||
|
|
||||||
|
def load_package_json(self, json_path=None):
|
||||||
|
if json_path is not None:
|
||||||
|
p_json = [json_path]
|
||||||
|
else:
|
||||||
|
p_json = glob.glob(os.path.join(self.project_dir(),
|
||||||
|
'package.json'))
|
||||||
|
setting_list = []
|
||||||
|
if p_json:
|
||||||
|
json_str = ''
|
||||||
|
with open(p_json[0], 'r') as f:
|
||||||
|
json_str = f.read()
|
||||||
|
try:
|
||||||
|
setting_list = self.load_from_json(json_str)
|
||||||
|
except ValueError as e: # Json file is invalid
|
||||||
|
log('Warning: Json file invalid.')
|
||||||
|
self.progress_text = '{}\n'.format(e)
|
||||||
|
return setting_list
|
||||||
|
|
||||||
|
def generate_json(self):
|
||||||
|
if 'webkit' not in self.original_packagejson:
|
||||||
|
self.original_packagejson['webkit'] = {}
|
||||||
|
if 'window' not in self.original_packagejson:
|
||||||
|
self.original_packagejson['window'] = {}
|
||||||
|
if 'webexe_settings' not in self.original_packagejson:
|
||||||
|
self.original_packagejson['webexe_settings'] = {}
|
||||||
|
|
||||||
|
dic = self.original_packagejson
|
||||||
|
|
||||||
|
for setting_name, setting in self.settings['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.settings['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.settings['webkit_settings'].items():
|
||||||
|
if setting.value is not None:
|
||||||
|
dic['webkit'][setting_name] = setting.value
|
||||||
|
|
||||||
|
dl_export_items = (self.settings['download_settings'].items() +
|
||||||
|
self.settings['export_settings'].items())
|
||||||
|
for setting_name, setting in dl_export_items:
|
||||||
|
if setting.value is not None:
|
||||||
|
dic['webexe_settings'][setting_name] = setting.value
|
||||||
|
|
||||||
|
s = json.dumps(dic, indent=4)
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
@property
|
||||||
|
def extract_error(self):
|
||||||
|
return self._extract_error
|
||||||
|
|
||||||
|
@extract_error.setter
|
||||||
|
def extract_error(self, value):
|
||||||
|
if value is not None and not self.quiet:
|
||||||
|
self._extract_error = str(value)
|
||||||
|
sys.stderr.write('\r{}'.format(self._extract_error))
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def output_err(self):
|
||||||
|
return self._output_err
|
||||||
|
|
||||||
|
@output_err.setter
|
||||||
|
def output_err(self, value):
|
||||||
|
if value is not None and not self.quiet:
|
||||||
|
self._output_err = str(value)
|
||||||
|
sys.stderr.write('\r{}'.format(self._output_err))
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def progress_text(self):
|
||||||
|
return self._progress_text
|
||||||
|
|
||||||
|
@progress_text.setter
|
||||||
|
def progress_text(self, value):
|
||||||
|
if value is not None and not self.quiet:
|
||||||
|
self._progress_text = str(value)
|
||||||
|
sys.stdout.write('\r{}'.format(self._progress_text))
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
def load_from_json(self, json_str):
|
||||||
|
dic = json.loads(json_str)
|
||||||
|
self.original_packagejson = dic
|
||||||
|
setting_list = []
|
||||||
|
stack = [('root', dic)]
|
||||||
|
while stack:
|
||||||
|
parent, new_dic = stack.pop()
|
||||||
|
for item in new_dic:
|
||||||
|
setting = self.get_setting(item)
|
||||||
|
if setting:
|
||||||
|
setting_list.append(setting)
|
||||||
|
if (setting.type == 'file' or
|
||||||
|
setting.type == 'string' or
|
||||||
|
setting.type == 'folder'):
|
||||||
|
val_str = self.convert_val_to_str(new_dic[item])
|
||||||
|
setting.value = val_str
|
||||||
|
if setting.type == 'check':
|
||||||
|
setting.value = new_dic[item]
|
||||||
|
if setting.type == 'list':
|
||||||
|
val_str = self.convert_val_to_str(new_dic[item])
|
||||||
|
setting.value = val_str
|
||||||
|
if isinstance(new_dic[item], dict):
|
||||||
|
stack.append((item, new_dic[item]))
|
||||||
|
return setting_list
|
||||||
|
|
||||||
|
def selected_version(self):
|
||||||
|
return self.get_setting('nw_version').value
|
||||||
|
|
||||||
|
def extract_files(self):
|
||||||
|
self.extract_error = None
|
||||||
|
location = self.get_setting('download_dir').value
|
||||||
|
version = self.selected_version()
|
||||||
|
for setting_name, setting in self.settings['export_settings'].items():
|
||||||
|
save_file_path = setting.save_file_path(version,
|
||||||
|
location)
|
||||||
|
try:
|
||||||
|
if setting.value:
|
||||||
|
extract_path = os.path.join('files', setting.name)
|
||||||
|
|
||||||
|
if os.path.exists(save_file_path):
|
||||||
|
setting_fbytes = setting.get_file_bytes(version)
|
||||||
|
for dest_file, fbytes in setting_fbytes:
|
||||||
|
with open(os.path.join(extract_path,
|
||||||
|
dest_file), 'wb+') as d:
|
||||||
|
d.write(fbytes)
|
||||||
|
self.progress_text += '.'
|
||||||
|
|
||||||
|
self.progress_text += '.'
|
||||||
|
|
||||||
|
except (tarfile.ReadError, zipfile.BadZipfile) as e:
|
||||||
|
if os.path.exists(save_file_path):
|
||||||
|
os.remove(save_file_path)
|
||||||
|
self.extract_error = e
|
||||||
|
# cannot use GUI in thread to notify user. Save it for later
|
||||||
|
self.progress_text = '\nDone.\n'
|
||||||
|
return True
|
||||||
|
|
||||||
|
def create_icns_for_app(self, icns_path):
|
||||||
|
icon_setting = self.get_setting('icon')
|
||||||
|
mac_app_icon_setting = self.get_setting('mac_icon')
|
||||||
|
icon_path = (mac_app_icon_setting.value
|
||||||
|
if mac_app_icon_setting.value
|
||||||
|
else icon_setting.value)
|
||||||
|
|
||||||
|
if icon_path:
|
||||||
|
icon_path = os.path.join(self.project_dir(), icon_path)
|
||||||
|
if not icon_path.endswith('.icns'):
|
||||||
|
save_icns(icon_path, icns_path)
|
||||||
|
else:
|
||||||
|
shutil.copy(icon_path, icns_path)
|
||||||
|
|
||||||
|
def replace_icon_in_exe(self, exe_path):
|
||||||
|
icon_setting = self.get_setting('icon')
|
||||||
|
exe_icon_setting = self.get_setting('exe_icon')
|
||||||
|
icon_path = (exe_icon_setting.value
|
||||||
|
if exe_icon_setting.value
|
||||||
|
else icon_setting.value)
|
||||||
|
if icon_path:
|
||||||
|
p = PEFile(exe_path)
|
||||||
|
p.replace_icon(os.path.join(self.project_dir(), icon_path))
|
||||||
|
p.write(exe_path)
|
||||||
|
p = None
|
||||||
|
|
||||||
|
def make_output_dirs(self):
|
||||||
|
self.output_err = ''
|
||||||
|
try:
|
||||||
|
self.progress_text = 'Removing old output directory...\n'
|
||||||
|
|
||||||
|
output_dir = os.path.join(self.output_dir(), self.project_name())
|
||||||
|
temp_dir = os.path.join(TEMP_DIR, 'webexectemp')
|
||||||
|
if os.path.exists(temp_dir):
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
|
||||||
|
self.progress_text = 'Making new directories...\n'
|
||||||
|
|
||||||
|
if not os.path.exists(output_dir):
|
||||||
|
os.makedirs(output_dir)
|
||||||
|
|
||||||
|
os.makedirs(temp_dir)
|
||||||
|
|
||||||
|
self.copy_files_to_project_folder()
|
||||||
|
|
||||||
|
json_file = os.path.join(self.project_dir(), 'package.json')
|
||||||
|
|
||||||
|
if self.output_package_json:
|
||||||
|
with open(json_file, 'w+') as f:
|
||||||
|
f.write(self.generate_json())
|
||||||
|
|
||||||
|
zip_file = os.path.join(temp_dir, self.project_name()+'.nw')
|
||||||
|
|
||||||
|
zip_files(zip_file, self.project_dir(), exclude_paths=[output_dir])
|
||||||
|
for ex_setting in self.settings['export_settings'].values():
|
||||||
|
if ex_setting.value:
|
||||||
|
self.progress_text = '\n'
|
||||||
|
name = ex_setting.display_name
|
||||||
|
self.progress_text = 'Making files for {}...'.format(name)
|
||||||
|
export_dest = os.path.join(output_dir, 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_text += '.'
|
||||||
|
|
||||||
|
if ex_setting.name == 'mac':
|
||||||
|
app_path = os.path.join(export_dest,
|
||||||
|
self.project_name()+'.app')
|
||||||
|
shutil.move(os.path.join(export_dest,
|
||||||
|
'node-webkit.app'),
|
||||||
|
app_path)
|
||||||
|
|
||||||
|
self.progress_text += '.'
|
||||||
|
|
||||||
|
shutil.copy(zip_file, os.path.join(app_path,
|
||||||
|
'Contents',
|
||||||
|
'Resources',
|
||||||
|
'app.nw'))
|
||||||
|
self.create_icns_for_app(os.path.join(app_path,
|
||||||
|
'Contents',
|
||||||
|
'Resources',
|
||||||
|
'nw.icns'))
|
||||||
|
|
||||||
|
self.progress_text += '.'
|
||||||
|
else:
|
||||||
|
ext = ''
|
||||||
|
windows = False
|
||||||
|
if ex_setting.name == 'windows':
|
||||||
|
ext = '.exe'
|
||||||
|
windows = True
|
||||||
|
|
||||||
|
nw_path = os.path.join(export_dest,
|
||||||
|
ex_setting.dest_files[0])
|
||||||
|
dest_binary_path = os.path.join(export_dest,
|
||||||
|
self.project_name() +
|
||||||
|
ext)
|
||||||
|
|
||||||
|
join_files(dest_binary_path, 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)
|
||||||
|
|
||||||
|
if windows:
|
||||||
|
self.replace_icon_in_exe(dest_binary_path)
|
||||||
|
|
||||||
|
self.progress_text += '.'
|
||||||
|
|
||||||
|
if os.path.exists(nw_path):
|
||||||
|
os.remove(nw_path)
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
exc = traceback.format_exception(sys.exc_info()[0],
|
||||||
|
sys.exc_info()[1],
|
||||||
|
sys.exc_info()[2])
|
||||||
|
self.output_err += ''.join(exc)
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
|
||||||
|
def copy_files_to_project_folder(self):
|
||||||
|
old_dir = CWD
|
||||||
|
os.chdir(self.project_dir())
|
||||||
|
for sgroup in self.settings['setting_groups']:
|
||||||
|
for setting in sgroup.values():
|
||||||
|
if setting.type == 'file' and setting.value:
|
||||||
|
f_path = setting.value.replace(self.project_dir(), '')
|
||||||
|
if not os.path.exists(f_path):
|
||||||
|
try:
|
||||||
|
shutil.copy(setting.value, self.project_dir())
|
||||||
|
setting.value = os.path.basename(setting.value)
|
||||||
|
except shutil.Error as e: # same file warning
|
||||||
|
log('Warning: {}'.format(e))
|
||||||
|
|
||||||
|
os.chdir(old_dir)
|
||||||
|
|
||||||
|
def convert_val_to_str(self, val):
|
||||||
|
if isinstance(val, (list, tuple)):
|
||||||
|
return ', '.join(val)
|
||||||
|
return str(val).replace(self.project_dir()+os.path.sep, '')
|
||||||
|
|
||||||
|
def export(self):
|
||||||
|
self.get_files_to_download()
|
||||||
|
res = self.try_to_download_files()
|
||||||
|
if res:
|
||||||
|
self.make_output_dirs()
|
||||||
|
self.progress_text = '\nDone!\n'
|
||||||
|
self.delete_files()
|
||||||
|
|
||||||
|
def get_files_to_download(self):
|
||||||
|
self.files_to_download = []
|
||||||
|
for setting_name, setting in self.settings['export_settings'].items():
|
||||||
|
if setting.value is True:
|
||||||
|
self.files_to_download.append(setting)
|
||||||
|
return True
|
||||||
|
|
||||||
|
def try_to_download_files(self):
|
||||||
|
if self.files_to_download:
|
||||||
|
return self.download_file_with_error_handling()
|
||||||
|
|
||||||
|
def continue_downloading_or_extract(self):
|
||||||
|
if self.files_to_download:
|
||||||
|
return self.download_file_with_error_handling()
|
||||||
|
else:
|
||||||
|
self.progress_text = 'Extracting files.'
|
||||||
|
return self.extract_files()
|
||||||
|
|
||||||
|
def download_file(self, path, setting):
|
||||||
|
|
||||||
|
location = self.get_setting('download_dir').value
|
||||||
|
|
||||||
|
url = path
|
||||||
|
file_name = setting.save_file_path(self.selected_version(), location)
|
||||||
|
|
||||||
|
archive_exists = os.path.exists(file_name)
|
||||||
|
|
||||||
|
dest_files_exist = False
|
||||||
|
|
||||||
|
forced = self.get_setting('force_download').value
|
||||||
|
|
||||||
|
if (archive_exists or dest_files_exist) and not forced:
|
||||||
|
return self.continue_downloading_or_extract()
|
||||||
|
|
||||||
|
web_file = urllib2.urlopen(url)
|
||||||
|
f = open(file_name, 'wb')
|
||||||
|
meta = web_file.info()
|
||||||
|
file_size = int(meta.getheaders("Content-Length")[0])
|
||||||
|
|
||||||
|
version = self.selected_version()
|
||||||
|
version_file = self.settings['base_url'].format(version)
|
||||||
|
short_name = path.replace(version_file, '')
|
||||||
|
MB = file_size/1000000.0
|
||||||
|
self.progress_text = ('Downloading: {}, '
|
||||||
|
'Size: {:.2f} MB\n'.format(short_name,
|
||||||
|
MB))
|
||||||
|
|
||||||
|
file_size_dl = 0
|
||||||
|
block_sz = 8192
|
||||||
|
while True:
|
||||||
|
buff = web_file.read(block_sz)
|
||||||
|
if not buff:
|
||||||
|
break
|
||||||
|
|
||||||
|
file_size_dl += len(buff)
|
||||||
|
DL_MB = file_size_dl/1000000.0
|
||||||
|
percent = file_size_dl*100.0/file_size
|
||||||
|
f.write(buff)
|
||||||
|
args = (DL_MB, MB, percent)
|
||||||
|
status = "{:10.2f}/{:.2f} MB [{:3.2f}%]".format(*args)
|
||||||
|
self.progress_text = status
|
||||||
|
|
||||||
|
self.progress_text = '\nDone downloading.\n'
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
return self.continue_downloading_or_extract()
|
||||||
|
|
||||||
|
def delete_files(self):
|
||||||
|
for ex_setting in self.settings['export_settings'].values():
|
||||||
|
for dest_file in ex_setting.dest_files:
|
||||||
|
f_path = os.path.join('files', ex_setting.name, dest_file)
|
||||||
|
if os.path.exists(f_path):
|
||||||
|
os.remove(f_path)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
import argparse
|
||||||
|
parser = argparse.ArgumentParser(description=('Command line interface '
|
||||||
|
'to web2exe'),
|
||||||
|
prog='web2execmd')
|
||||||
|
command_base = CommandBase()
|
||||||
|
parser.add_argument('project_dir', metavar='project_dir',
|
||||||
|
help='The project directory.')
|
||||||
|
parser.add_argument('--output-dir', dest='output_dir',
|
||||||
|
help='The output directory for exports.')
|
||||||
|
parser.add_argument('--quiet', dest='quiet', action='store_true',
|
||||||
|
default=False,
|
||||||
|
help='Silences output messages')
|
||||||
|
parser.add_argument('--package-json',
|
||||||
|
dest='load_json',
|
||||||
|
nargs='?',
|
||||||
|
default='',
|
||||||
|
const=True,
|
||||||
|
help=('Loads the package.json '
|
||||||
|
'file in the project directory. '
|
||||||
|
'Ignores other command line arguments.'))
|
||||||
|
|
||||||
|
for setting_group_dict in command_base.settings['setting_groups']:
|
||||||
|
for setting_name, setting in setting_group_dict.items():
|
||||||
|
kwargs = {}
|
||||||
|
if setting_name == 'name':
|
||||||
|
kwargs.update({'default': command_base.project_name})
|
||||||
|
else:
|
||||||
|
kwargs.update({'required': setting.required,
|
||||||
|
'default': setting.default_value})
|
||||||
|
action = 'store'
|
||||||
|
option_name = setting_name.replace('_', '-')
|
||||||
|
if isinstance(setting.default_value, bool):
|
||||||
|
action = ('store_true' if setting.default_value is False
|
||||||
|
else 'store_false')
|
||||||
|
kwargs.update({'action': action})
|
||||||
|
if setting.default_value is True:
|
||||||
|
option_name = 'disable-{}'.format(option_name)
|
||||||
|
else:
|
||||||
|
kwargs.update({'choices': setting.values or None,
|
||||||
|
'metavar': '<{}>'.format(setting.display_name)})
|
||||||
|
|
||||||
|
parser.add_argument('--{}'.format(option_name),
|
||||||
|
dest=setting_name,
|
||||||
|
help=setting.description,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
export_args = [arg for arg in command_base.settings['export_settings']]
|
||||||
|
parser.add_argument('--export-to', dest='export_options',
|
||||||
|
nargs='+', required=True,
|
||||||
|
choices=export_args,
|
||||||
|
help=('Choose at least one system '
|
||||||
|
'to export to.'))
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if args.quiet:
|
||||||
|
command_base.quiet = True
|
||||||
|
|
||||||
|
command_base._project_dir = args.project_dir
|
||||||
|
command_base._output_dir = (args.output_dir or
|
||||||
|
os.path.join(args.project_dir, 'output'))
|
||||||
|
|
||||||
|
if not args.title:
|
||||||
|
args.title = command_base.project_name()
|
||||||
|
|
||||||
|
for name, val in args._get_kwargs():
|
||||||
|
if callable(val):
|
||||||
|
val = val()
|
||||||
|
if name == 'export_options':
|
||||||
|
for opt in val:
|
||||||
|
setting = command_base.get_setting(opt)
|
||||||
|
if setting is not None:
|
||||||
|
setting.value = True
|
||||||
|
else:
|
||||||
|
setting = command_base.get_setting(name)
|
||||||
|
if setting is not None:
|
||||||
|
setting.value = val
|
||||||
|
|
||||||
|
if args.load_json is True:
|
||||||
|
command_base.load_package_json()
|
||||||
|
elif args.load_json:
|
||||||
|
command_base.load_package_json(args.load_json)
|
||||||
|
|
||||||
|
command_base.export()
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
|
0.11.3
|
||||||
|
0.11.2
|
||||||
|
0.11.1
|
||||||
0.11.0-rc1
|
0.11.0-rc1
|
||||||
0.11.0
|
0.11.0
|
||||||
0.10.5
|
0.10.5
|
||||||
|
|
|
||||||
220
files/settings.cfg
Normal file
220
files/settings.cfg
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
base_url='http://dl.node-webkit.org/v{}/'
|
||||||
|
win_32_dir_prefix = 'node-webkit-v{}-win-ia32'
|
||||||
|
mac_32_dir_prefix = 'node-webkit-v{}-osx-ia32'
|
||||||
|
linux_32_dir_prefix = 'node-webkit-v{}-linux-ia32'
|
||||||
|
|
||||||
|
win_64_dir_prefix = 'node-webkit-v{}-win-x64'
|
||||||
|
mac_64_dir_prefix = 'node-webkit-v{}-osx-x64'
|
||||||
|
linux_64_dir_prefix = 'node-webkit-v{}-linux-x64'
|
||||||
|
|
||||||
|
[setting_groups]
|
||||||
|
[[app_settings]]
|
||||||
|
[[[main]]]
|
||||||
|
display_name='Main html file'
|
||||||
|
required=True
|
||||||
|
type='file'
|
||||||
|
file_types='*.html *.php *.htm'
|
||||||
|
description='Main html file relative to the project directory.'
|
||||||
|
[[[name]]]
|
||||||
|
display_name='App Name'
|
||||||
|
required=True
|
||||||
|
type='string'
|
||||||
|
[[[description]]]
|
||||||
|
default_value=''
|
||||||
|
type='string'
|
||||||
|
[[[version]]]
|
||||||
|
default_value='0.1.0'
|
||||||
|
type='string'
|
||||||
|
[[[keywords]]]
|
||||||
|
default_value=''
|
||||||
|
type='string'
|
||||||
|
[[[nodejs]]]
|
||||||
|
display_name='Include Nodejs'
|
||||||
|
default_value=True
|
||||||
|
type='check'
|
||||||
|
[[[node-main]]]
|
||||||
|
display_name='Alt. Nodejs'
|
||||||
|
default_value=''
|
||||||
|
type='file'
|
||||||
|
file_types='*.js'
|
||||||
|
[[[single-instance]]]
|
||||||
|
display_name='Single Instance'
|
||||||
|
default_value=True
|
||||||
|
type='check'
|
||||||
|
description='Restrict the app to run with only a single instance allowed at a time.'
|
||||||
|
|
||||||
|
[[webkit_settings]]
|
||||||
|
[[[plugin]]]
|
||||||
|
display_name='Load Plugins'
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
[[[java]]]
|
||||||
|
display_name='Load Java'
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
[[[page-cache]]]
|
||||||
|
display_name='Page Cache'
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
|
||||||
|
[[window_settings]]
|
||||||
|
[[[title]]]
|
||||||
|
default_value=''
|
||||||
|
type='string'
|
||||||
|
[[[icon]]]
|
||||||
|
display_name='Window Icon'
|
||||||
|
default_value=''
|
||||||
|
type='file'
|
||||||
|
file_types='*.png *.jpg *.jpeg'
|
||||||
|
[[[mac_icon]]]
|
||||||
|
default_value=''
|
||||||
|
type='file'
|
||||||
|
file_types='*.png *.jpg *.jpeg *.icns'
|
||||||
|
description='This icon to be displayed for the Mac Application. Defaults to Window Icon'
|
||||||
|
[[[exe_icon]]]
|
||||||
|
default_value=''
|
||||||
|
type='file'
|
||||||
|
file_types='*.png *.jpg *.jpeg'
|
||||||
|
description='This icon to be displayed for the windows exe of the app. Defaults to Winodow icon.'
|
||||||
|
[[[width]]]
|
||||||
|
default_value='640'
|
||||||
|
type='string'
|
||||||
|
[[[height]]]
|
||||||
|
default_value='480'
|
||||||
|
type='string'
|
||||||
|
[[[min_width]]]
|
||||||
|
default_value=None
|
||||||
|
type='string'
|
||||||
|
[[[min_height]]]
|
||||||
|
default_value=None
|
||||||
|
type='string'
|
||||||
|
[[[max_width]]]
|
||||||
|
default_value=None
|
||||||
|
type='string'
|
||||||
|
[[[max_height]]]
|
||||||
|
default_value=None
|
||||||
|
type='string'
|
||||||
|
[[[toolbar]]]
|
||||||
|
display_name='Show Toolbar'
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description=''
|
||||||
|
[[[always-on-top]]]
|
||||||
|
display_name='Keep on Top'
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description=''
|
||||||
|
[[[frame]]]
|
||||||
|
display_name='Window Frame'
|
||||||
|
default_value=True
|
||||||
|
type='check'
|
||||||
|
description='Hide the frame of the window'
|
||||||
|
[[[show_in_taskbar]]]
|
||||||
|
display_name='Taskbar'
|
||||||
|
default_value=True
|
||||||
|
type='check'
|
||||||
|
description='Hide the app running in the taskbar'
|
||||||
|
[[[visible]]]
|
||||||
|
default_value=True
|
||||||
|
type='check'
|
||||||
|
description=''
|
||||||
|
[[[resizable]]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description=''
|
||||||
|
[[[fullscreen]]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description=''
|
||||||
|
[[[position]]]
|
||||||
|
display_name='Position by'
|
||||||
|
default_value=None
|
||||||
|
values=[None, 'mouse', 'center']
|
||||||
|
type='list'
|
||||||
|
description='The position to place the window when it opens.'
|
||||||
|
[[[as_desktop]]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description='Tries to render the app to the desktop background'
|
||||||
|
[[[transparent]]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
description='Allows window tranparency.'
|
||||||
|
|
||||||
|
[[download_settings]]
|
||||||
|
[[[nw_version]]]
|
||||||
|
display_name='Node-webkit version'
|
||||||
|
default_value='0.9.2'
|
||||||
|
values=[]
|
||||||
|
type='list'
|
||||||
|
button='Update'
|
||||||
|
button_callback='update_nw_versions'
|
||||||
|
[[[force_download]]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
[[[download_dir]]]
|
||||||
|
display_name='Download location'
|
||||||
|
default_value='{DEFAULT_DOWNLOAD_PATH}'
|
||||||
|
type='folder'
|
||||||
|
|
||||||
|
[export_settings]
|
||||||
|
[[windows]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
url='%(base_url)s%(win_32_dir_prefix)s.zip'
|
||||||
|
extract_files="""['%(win_32_dir_prefix)s/nw.exe',
|
||||||
|
'%(win_32_dir_prefix)s/icudtl.dat',
|
||||||
|
'%(win_32_dir_prefix)s/libEGL.dll',
|
||||||
|
'%(win_32_dir_prefix)s/libGLESv2.dll']"""
|
||||||
|
dest_files="""['nw.exe',
|
||||||
|
'nw.pak',
|
||||||
|
'icudtl.dat',
|
||||||
|
'libEGL.dll',
|
||||||
|
'libGLESv2.dll']"""
|
||||||
|
[[mac]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
url='%(base_url)s%(mac_32_dir_prefix)s.zip'
|
||||||
|
extract_file='%(mac_32_dir_prefix)s/node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/node-webkit Framework'
|
||||||
|
extract_files="""['%(mac_32_dir_prefix)s/node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/node-webkit Framework',
|
||||||
|
'%(mac_32_dir_prefix)s/node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/Resources/nw.pak',
|
||||||
|
'%s(mac_32_dir_prefix)s/node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/Resources/icudtl.dat']"""
|
||||||
|
dest_files="""['node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/node-webkit Framework',
|
||||||
|
'node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/Resources/nw.pak',
|
||||||
|
'node-webkit.app/Contents/Frameworks/node-webkit Framework.framework/Resources/icudtl.dat']"""
|
||||||
|
|
||||||
|
[[linux-x64]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
url='%(base_url)s%(linux_64_dir_prefix)s.tar.gz'
|
||||||
|
extract_file='%(linux_64_dir_prefix)s/nw'
|
||||||
|
extract_files="""['%(linux_64_dir_prefix)s/nw',
|
||||||
|
'%(linux_64_dir_prefix)s/nw.pak',
|
||||||
|
'%(linux_64_dir_prefix)s/icudtl.dat']"""
|
||||||
|
dest_files=['nw', 'nw.pak', 'icudtl.dat']
|
||||||
|
[[linux-x32]]
|
||||||
|
default_value=False
|
||||||
|
type='check'
|
||||||
|
url='%(base_url)s%(linux_32_dir_prefix)s.tar.gz'
|
||||||
|
extract_file='%(linux_32_dir_prefix)s/nw'
|
||||||
|
extract_files="""['%(linux_32_dir_prefix)s/nw',
|
||||||
|
'%(linux_32_dir_prefix)s/nw.pak',
|
||||||
|
'%(linux_32_dir_prefix)s/icudtl.dat']"""
|
||||||
|
dest_files=['nw', 'nw.pak', 'icudtl.dat']
|
||||||
|
|
||||||
|
[order]
|
||||||
|
application_setting_order="""['main', 'name', 'node-main', 'description', 'version', 'keywords',
|
||||||
|
'nodejs', 'single-instance', 'plugin',
|
||||||
|
'java', 'page-cache']"""
|
||||||
|
window_setting_order = """['title', 'icon', 'mac_icon', 'exe_icon', 'position', 'width', 'height',
|
||||||
|
'min_width', 'min_height',
|
||||||
|
'max_width', 'max_height', 'toolbar', 'always-on-top', 'frame',
|
||||||
|
'show_in_taskbar', 'visible', 'resizable', 'fullscreen', 'as_desktop',
|
||||||
|
'transparent']"""
|
||||||
|
|
||||||
|
export_setting_order = """['windows', 'linux-x64', 'mac', 'linux-x32']"""
|
||||||
|
|
||||||
|
download_setting_order = """['nw_version', 'download_dir','force_download']"""
|
||||||
|
|
||||||
|
[version_info]
|
||||||
|
url='https://raw.githubusercontent.com/rogerwang/node-webkit/master/CHANGELOG.md'
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import struct
|
import struct
|
||||||
from image_utils import Image, nearest_icon_size, resize
|
import image_utils
|
||||||
import png
|
import png
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -638,7 +638,10 @@ class ICNSHeader(Structure):
|
||||||
self.elements = []
|
self.elements = []
|
||||||
|
|
||||||
def parse_image(self, image):
|
def parse_image(self, image):
|
||||||
icon_size = nearest_icon_size(image.size[0], image.size[1])
|
if not image_utils.IMAGE_UTILS_AVAILABLE:
|
||||||
|
return None
|
||||||
|
|
||||||
|
icon_size = image_utils.nearest_icon_size(image.size[0], image.size[1])
|
||||||
|
|
||||||
icon_sizes = [icon_size]
|
icon_sizes = [icon_size]
|
||||||
|
|
||||||
|
|
@ -649,7 +652,7 @@ class ICNSHeader(Structure):
|
||||||
for icon_s in icon_sizes:
|
for icon_s in icon_sizes:
|
||||||
icns_element = ICNSElement()
|
icns_element = ICNSElement()
|
||||||
|
|
||||||
im_data = resize(image, (icon_s, icon_s))
|
im_data = image_utils.resize(image, (icon_s, icon_s))
|
||||||
|
|
||||||
png_file = png.Reader(bytes=im_data)
|
png_file = png.Reader(bytes=im_data)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from cStringIO import StringIO
|
from cStringIO import StringIO
|
||||||
try:
|
try:
|
||||||
from PIL import Image as im
|
from PIL import Image as im
|
||||||
|
IMAGE_UTILS_AVAILABLE = True
|
||||||
Image = im.open
|
Image = im.open
|
||||||
def resize(image, size):
|
def resize(image, size):
|
||||||
output = StringIO()
|
output = StringIO()
|
||||||
|
|
@ -17,7 +18,7 @@ try:
|
||||||
output.close()
|
output.close()
|
||||||
return contents
|
return contents
|
||||||
except ImportError:
|
except ImportError:
|
||||||
raise Exception('Python image library PIL/pillow is required.')
|
IMAGE_UTILS_AVAILABLE = False
|
||||||
|
|
||||||
LARGEST_ICON_SIZE = 1024
|
LARGEST_ICON_SIZE = 1024
|
||||||
SMALLEST_ICON_SIZE = 16
|
SMALLEST_ICON_SIZE = 16
|
||||||
|
|
|
||||||
7
pycns.py
7
pycns.py
|
|
@ -1,5 +1,5 @@
|
||||||
from icns_info import *
|
from icns_info import *
|
||||||
from image_utils import Image, nearest_icon_size, resize
|
from image_utils import Image
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
"""This module takes any image that is readable by PIL and exports it to an icns file.
|
"""This module takes any image that is readable by PIL and exports it to an icns file.
|
||||||
|
|
@ -15,8 +15,9 @@ def encode_image_to_icns(image_path):
|
||||||
|
|
||||||
def save_icns(image_path, icns_path):
|
def save_icns(image_path, icns_path):
|
||||||
im_data = encode_image_to_icns(image_path)
|
im_data = encode_image_to_icns(image_path)
|
||||||
icns_path = icns_path if icns_path.endswith('.icns') else icns_path+'.icns'
|
if im_data is not None:
|
||||||
open(icns_path, 'wb+').write(im_data)
|
icns_path = icns_path if icns_path.endswith('.icns') else icns_path+'.icns'
|
||||||
|
open(icns_path, 'wb+').write(im_data)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
if len(sys.argv) != 3:
|
if len(sys.argv) != 3:
|
||||||
|
|
|
||||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
pillow
|
||||||
|
pyside
|
||||||
|
configobj
|
||||||
37
utils.py
37
utils.py
|
|
@ -3,6 +3,12 @@ import os, zipfile, io, platform
|
||||||
import sys, tempfile
|
import sys, tempfile
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
try:
|
||||||
|
import zlib
|
||||||
|
ZIP_MODE = zipfile.ZIP_DEFLATED
|
||||||
|
except:
|
||||||
|
ZIP_MODE = zipfile.ZIP_STORED
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
def is_windows():
|
def is_windows():
|
||||||
|
|
@ -15,7 +21,6 @@ def log(*args):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(*args)
|
print(*args)
|
||||||
|
|
||||||
|
|
||||||
def open_folder_in_explorer(path):
|
def open_folder_in_explorer(path):
|
||||||
if platform.system() == "Windows":
|
if platform.system() == "Windows":
|
||||||
os.startfile(path)
|
os.startfile(path)
|
||||||
|
|
@ -25,7 +30,7 @@ def open_folder_in_explorer(path):
|
||||||
subprocess.Popen(["xdg-open", path])
|
subprocess.Popen(["xdg-open", path])
|
||||||
|
|
||||||
def zip_files(zip_file_name, *args, **kwargs):
|
def zip_files(zip_file_name, *args, **kwargs):
|
||||||
zip_file = zipfile.ZipFile(zip_file_name, 'w')
|
zip_file = zipfile.ZipFile(zip_file_name, 'w', ZIP_MODE)
|
||||||
verbose = kwargs.pop('verbose', False)
|
verbose = kwargs.pop('verbose', False)
|
||||||
exclude_paths = kwargs.pop('exclude_paths', [])
|
exclude_paths = kwargs.pop('exclude_paths', [])
|
||||||
old_path = os.getcwd()
|
old_path = os.getcwd()
|
||||||
|
|
@ -55,7 +60,7 @@ def zip_files(zip_file_name, *args, **kwargs):
|
||||||
|
|
||||||
else:
|
else:
|
||||||
file = os.path.abspath(arg)
|
file = os.path.abspath(arg)
|
||||||
directory = os.path.abspath(os.path.join(file,'..'))
|
directory = os.path.abspath(os.path.join(file, '..'))
|
||||||
os.chdir(directory)
|
os.chdir(directory)
|
||||||
file_loc = os.path.relpath(arg, directory)
|
file_loc = os.path.relpath(arg, directory)
|
||||||
if verbose:
|
if verbose:
|
||||||
|
|
@ -76,29 +81,3 @@ def join_files(destination, *args, **kwargs):
|
||||||
if len(bytes) == 0:
|
if len(bytes) == 0:
|
||||||
break
|
break
|
||||||
dest_file.write(bytes)
|
dest_file.write(bytes)
|
||||||
|
|
||||||
#def convert_icns_to_png(inputname, outputname, size=0, out_type='png'):
|
|
||||||
# try:
|
|
||||||
# # new_from_file_at_size() does not work, requires incremental loader
|
|
||||||
# pixbuf = GdkPixbuf.Pixbuf.new_from_file(inputname)
|
|
||||||
# if size:
|
|
||||||
# width, height = pixbuf.get_width(), pixbuf.get_height()
|
|
||||||
# if width > height:
|
|
||||||
# if width > size:
|
|
||||||
# height = height * size / width
|
|
||||||
# width = size
|
|
||||||
# else:
|
|
||||||
# if height > size:
|
|
||||||
# width = width * size / height
|
|
||||||
# height = size
|
|
||||||
#
|
|
||||||
# scaled = GdkPixbuf.Pixbuf.scale_simple(pixbuf, width, height,
|
|
||||||
# GdkPixbuf.InterpType.BILINEAR)
|
|
||||||
# else:
|
|
||||||
# scaled = pixbuf
|
|
||||||
#
|
|
||||||
# scaled.savev(outputname, out_type, [], [])
|
|
||||||
#
|
|
||||||
# except GLib.GError as e:
|
|
||||||
# sys.stderr.write("%s:%d: %s\n" % (e.domain, e.code, e))
|
|
||||||
# return e.code
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue