From 3452995c19c7a6115a464a3fdb9ff994b50131e3 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Sat, 10 Dec 2016 22:00:22 -0700 Subject: [PATCH 1/3] Add preliminary file tree --- main.py | 33 ++++++++++++- util_classes.py | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index b0a5c30..47c32e4 100644 --- a/main.py +++ b/main.py @@ -37,6 +37,7 @@ from util_classes import ExistingProjectDialog from util_classes import BackgroundThread, Validator from util_classes import CompleterLineEdit, TagsCompleter +from util_classes import TreeBrowser from PySide import QtGui, QtCore from PySide.QtGui import (QApplication, QHBoxLayout, QVBoxLayout) @@ -989,6 +990,9 @@ def load_project(self, directory, readonly=False): self.set_window_icon() self.open_export_button.setEnabled(True) + + self.tree_browser.init(directory, ['.*']) + self.update_json = True def init_main_field(self, directory): @@ -1159,7 +1163,7 @@ def create_export_settings(self): ex_setting_order = self.settings['order']['export_setting_order'] - vlayout = self.create_layout(ex_setting_order, cols=4) + vlayout = self.create_layout(ex_setting_order, cols=1) output_name_layout = self.create_output_name_pattern_line() @@ -1167,8 +1171,24 @@ def create_export_settings(self): script_layout = self.create_script_layout() + hlayout = QtGui.QHBoxLayout() + + platform_group = QtGui.QGroupBox('Platforms') + playout = QtGui.QVBoxLayout() + playout.addLayout(vlayout) + platform_group.setLayout(playout) + + hlayout.addWidget(platform_group) + + tree_layout = self.create_blacklist_layout() + + tree_group = QtGui.QGroupBox('Files') + tree_group.setLayout(tree_layout) + + hlayout.addWidget(tree_group) + vbox = QtGui.QVBoxLayout() - vbox.addLayout(vlayout) + vbox.addLayout(hlayout) vbox.addLayout(output_name_layout) vbox.addLayout(output_layout) vbox.addLayout(script_layout) @@ -1176,6 +1196,15 @@ def create_export_settings(self): group_box.setLayout(vbox) return group_box + def create_blacklist_layout(self): + blacklist_layout = QtGui.QVBoxLayout() + + self.tree_browser = TreeBrowser() + + blacklist_layout.addWidget(self.tree_browser) + + return blacklist_layout + def create_output_name_pattern_line(self): output_name_layout = QtGui.QHBoxLayout() diff --git a/util_classes.py b/util_classes.py index ef7e152..82ffdcf 100644 --- a/util_classes.py +++ b/util_classes.py @@ -9,6 +9,129 @@ import utils from PySide import QtGui, QtCore +from PySide.QtCore import Qt + +class FileItem(QtGui.QTreeWidgetItem): + def __init__(self, parent=None, path=None): + super(FileItem, self).__init__(parent) + self.path = path + +class TreeBrowser(QtGui.QWidget): + def __init__(self, directory=None, checked_files=None, + whitelist=None, blacklist=None, parent=None): + super(TreeBrowser, self).__init__(parent=parent) + self.root = QtGui.QTreeWidget() + self.root.setHeaderLabel('Included files') + self.root.itemChanged.connect(self.item_changed) + self.files = {} + + self.paths = [] + + layout = QtGui.QVBoxLayout() + layout.addWidget(self.root) + self.setLayout(layout) + + self.watcher = QtCore.QFileSystemWatcher() + self.watcher.directoryChanged.connect(self.directory_changed) + self.watcher.fileChanged.connect(self.file_changed) + + self.directoryChanged = self.watcher.directoryChanged + self.fileChanged = self.watcher.fileChanged + + self.init(directory, checked_files, whitelist, blacklist) + + def init(self, directory=None, checked_files=None, + whitelist=None, blacklist=None): + + if directory: + self.directory = directory + os.sep + else: + self.directory = directory + + self.checked_files = checked_files or [] + + self.whitelist = whitelist or [] + self.blacklist = blacklist or [] + + self.watcher.removePaths(self.watcher.files()) + + self.files = {} + + self.root.clear() + + self.generate_directory_widget() + + def file_changed(self, path): + print(path) + pass + + def directory_changed(self, path): + print(path) + pass + + def get_abs_file_list(self): + return [os.path.join(self.directory, path) for path in self.files.keys()] + + def get_checked_files(self): + pass + + def item_changed(self, item, column): + self.files[item.path] = item.checkState(column) + + def generate_directory_widget(self): + if self.directory is None: + return + + parent_map = {'': self.root} + + for root, dirs, files in os.walk(self.directory): + for directory in dirs: + + proj_path = root.replace(self.directory, '') + + parent = parent_map[proj_path] + + path = os.path.join(proj_path, directory) + + checked = Qt.Unchecked + + for checked_file in self.checked_files: + match = re.match('^'+checked_file, path) + if match: + checked = Qt.Checked + + child = FileItem(parent, path) + child.setFlags(child.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) + child.setText(0, directory) + child.setCheckState(0, checked) + + self.files[path] = checked + + parent_map[path] = child + + for file in files: + proj_path = root.replace(self.directory, '') + + parent = parent_map[proj_path] + + path = os.path.join(proj_path, file) + + checked = Qt.Unchecked + + for checked_file in self.checked_files: + match = re.match(checked_file, path) + if match: + checked = Qt.Checked + + child = FileItem(parent, path) + child.setFlags(child.flags() | Qt.ItemIsUserCheckable) + child.setText(0, file) + child.setCheckState(0, checked) + + self.files[path] = checked + + self.watcher.addPaths(self.get_abs_file_list()) + class ExistingProjectDialog(QtGui.QDialog): def __init__(self, recent_projects, directory_callback, parent=None): @@ -93,6 +216,7 @@ def project_clicked(self, _): def cancelled(self): self.close() + class Validator(QtGui.QRegExpValidator): def __init__(self, regex, action, parent=None): self.exp = regex From 4aa74f5ad8c8076b4137ee9f9bcb43f857e92251 Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Tue, 13 Dec 2016 17:36:08 -0700 Subject: [PATCH 2/3] Fix #175: Nw versions not updating if version file is empty --- command_line.py | 2 +- main.py | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/command_line.py b/command_line.py index 2bbf137..0e75f43 100644 --- a/command_line.py +++ b/command_line.py @@ -89,7 +89,7 @@ def setup_nw_versions(self): for line in f: nw_version.values.append(line.strip()) except IOError: - nw_version.values.append(nw_version.default_value) + pass def get_nw_versions(self): """Get the already downloaded nw versions from the settings""" diff --git a/main.py b/main.py index 47c32e4..eb2eb94 100644 --- a/main.py +++ b/main.py @@ -210,18 +210,6 @@ def open_recent_file(self): if action: self.load_project(action.data()) - def setup_nw_versions(self): - """Loads stored versions that were previously retrieved.""" - nw_version = self.get_setting('nw_version') - try: - f = codecs.open(utils.get_data_file_path(config.VER_FILE), - encoding='utf-8') - for line in f: - nw_version.values.append(line.strip()) - f.close() - except IOError: - nw_version.values.append(nw_version.default_value) - def create_application_layout(self): """Create all widgets and set the central widget.""" self.main_layout = QtGui.QVBoxLayout() From c6b8a60d79376c2c2e449f0204c16fb60223a02e Mon Sep 17 00:00:00 2001 From: Joey Payne Date: Tue, 13 Dec 2016 20:25:46 -0700 Subject: [PATCH 3/3] Close #173: Add blacklisting and whitelisting to project directory Files can be whitelisted or blacklisted via globs. A file tree on the right hand side shows which files are currently included in the build. --- command_line.py | 58 ++++++++-- files/settings.cfg | 11 ++ main.py | 108 ++++++++++++++++--- util_classes.py | 261 +++++++++++++++++++++++++++++++++------------ utils.py | 13 +-- 5 files changed, 352 insertions(+), 99 deletions(-) diff --git a/command_line.py b/command_line.py index 0e75f43..ae38dba 100644 --- a/command_line.py +++ b/command_line.py @@ -43,7 +43,7 @@ import utils from utils import zip_files, join_files from utils import get_data_path, get_data_file_path -from util_classes import Setting +from util_classes import Setting, FileTree from image_utils.pycns import save_icns from pepy.pe import PEFile @@ -69,6 +69,8 @@ def __init__(self, quiet=False): self.readonly = True self.update_json = True + self.file_tree = FileTree() + def init(self): self.logger = config.logger self.update_nw_versions(None) @@ -320,6 +322,7 @@ def get_versions(self): nw_version = self.get_setting('nw_version') old_versions = set(nw_version.values) + old_versions = old_versions.union(union_versions) new_versions = set(re.findall(regex, html)) @@ -375,7 +378,7 @@ def download_file_with_error_handling(self): if os.path.exists(setting.save_file_path(version, location)): os.remove(setting.save_file_path(version, location)) - exc_format = utils.format_exc_info(sys.exc_info) + exc_format = utils.format_exc_info(sys.exc_info()) self.show_error(exc_format) self.enable_ui_after_error() @@ -758,8 +761,12 @@ def replace_plist(self, app_path): plist_dict['CFBundleDisplayName'] = self.project_name() plist_dict['CFBundleName'] = self.project_name() version_setting = self.get_setting('version') - plist_dict['CFBundleShortVersionString'] = version_setting.value - plist_dict['CFBundleVersion'] = version_setting.value + if version_setting.value is not None: + plist_dict['CFBundleShortVersionString'] = version_setting.value + plist_dict['CFBundleVersion'] = version_setting.value + else: + plist_dict['CFBundleShortVersionString'] = '0.0.0' + plist_dict['CFBundleVersion'] = '0.0.0' plistlib.writePlist(plist_dict, plist_path) @@ -870,6 +877,13 @@ def process_export_setting(self, ex_setting, output_name): self.process_win_linux_setting(app_loc, output_dir, ex_setting) + @property + def used_project_files(self): + return self.file_tree.files + + @property + def used_project_dirs(self): + return self.file_tree.dirs def make_output_dirs(self, write_json=True): """Create the output directories for the application to be copied""" @@ -878,6 +892,17 @@ def make_output_dirs(self, write_json=True): self.progress_text = 'Making new directories...\n' + + whitelist_setting = self.get_setting('whitelist') + blacklist_setting = self.get_setting('blacklist') + + output_blacklist = os.path.basename(self.output_dir()) + + self.file_tree.init(self.project_dir(), + blacklist=(blacklist_setting.value.split(',') + + ['*'+output_blacklist+'*']), + whitelist=whitelist_setting.value.split(',')) + self.copy_files_to_project_folder() if write_json: @@ -914,15 +939,28 @@ def get_app_nw_loc(self, temp_dir, output_dir): """Copy the temporary app to the output_dir""" app_file = utils.path_join(temp_dir, self.project_name()+'.nw') + proj_dir = self.project_dir() + if self.uncompressed: app_nw_folder = utils.path_join(temp_dir, self.project_name()+'.nwf') + for dir in self.used_project_dirs: + if not os.path.exists(dir): + os.makedirs(dir) + + for file in self.used_project_files: + src = utils.path_join(proj_dir, file) + dest = utils.path_join(app_nw_folder, file) + + base, _ = os.path.split(dest) + + if not os.path.exists(base): + os.makedirs(base) - utils.copytree(self.project_dir(), app_nw_folder, - ignore=shutil.ignore_patterns(output_dir)) + utils.copy(src, dest) return app_nw_folder else: - zip_files(app_file, self.project_dir(), exclude_paths=[output_dir]) + zip_files(app_file, proj_dir, *self.used_project_files) return app_file def get_version_tuple(self): @@ -1455,7 +1493,6 @@ class ArgParser(argparse.ArgumentParser): """Custom argparser that prints help if there is an error""" def error(self, message): sys.stderr.write('error: {}\n'.format(message)) - self.print_help() sys.exit(2) def get_arguments(command_base): @@ -1520,8 +1557,9 @@ def generate_setting_args(command_base, parser): if setting_name == 'name': kwargs.update({'default': command_base.project_name}) else: - kwargs.update({'required': setting.required, - 'default': setting.default_value}) + kwargs.update({'required': setting.required}) + if setting.default_value is not None: + kwargs.update({'default': setting.default_value}) action = 'store' option_name = setting_name.replace('_', '-') diff --git a/files/settings.cfg b/files/settings.cfg index 8ecb7a2..15f481e 100644 --- a/files/settings.cfg +++ b/files/settings.cfg @@ -128,6 +128,16 @@ linux_64_dir_prefix = 'nwjs-v{}-linux-x64' default_value='' type='string' description='Type "%(" to see a list of options to reference. Name your output folder.\n Include slashes to make sub-directories.' + [[[blacklist]]] + display_name='Blacklist' + default_value='' + type='string' + description='Glob-style blacklist files/directories. Each line is a new pattern. Ex: *.jpeg, .git, *file[s].txt' + [[[whitelist]]] + display_name='Whitelist' + default_value='' + type='string' + description='Glob-style whitelist files/directories. Each line is a new pattern. Ex: *.jpeg, .git, *file[s].txt.\nWhitelist trumps blacklist.' [[window_settings]] [[[id]]] @@ -238,6 +248,7 @@ linux_64_dir_prefix = 'nwjs-v{}-linux-x64' [[download_settings]] [[[nw_version]]] display_name='NW.js version' + required=True default_value=None values=[] type='list' diff --git a/main.py b/main.py index eb2eb94..988cd0e 100644 --- a/main.py +++ b/main.py @@ -979,7 +979,13 @@ def load_project(self, directory, readonly=False): self.set_window_icon() self.open_export_button.setEnabled(True) - self.tree_browser.init(directory, ['.*']) + blacklist_setting = self.get_setting('blacklist') + + output_blacklist = os.path.basename(self.output_dir()) + + self.tree_browser.init(directory, + blacklist=(blacklist_setting.value.split('\n') + + ['*'+output_blacklist+'*'])) self.update_json = True @@ -1152,6 +1158,7 @@ def create_export_settings(self): ex_setting_order = self.settings['order']['export_setting_order'] vlayout = self.create_layout(ex_setting_order, cols=1) + vlayout.setContentsMargins(0, 10, 0, 0) output_name_layout = self.create_output_name_pattern_line() @@ -1162,18 +1169,15 @@ def create_export_settings(self): hlayout = QtGui.QHBoxLayout() platform_group = QtGui.QGroupBox('Platforms') + platform_group.setContentsMargins(0, 10, 0, 0) playout = QtGui.QVBoxLayout() playout.addLayout(vlayout) platform_group.setLayout(playout) hlayout.addWidget(platform_group) - tree_layout = self.create_blacklist_layout() - - tree_group = QtGui.QGroupBox('Files') - tree_group.setLayout(tree_layout) - - hlayout.addWidget(tree_group) + tree_layout = self.create_blacklist_layout(hlayout) + tree_layout.setContentsMargins(0, 10, 0, 0) vbox = QtGui.QVBoxLayout() vbox.addLayout(hlayout) @@ -1184,15 +1188,85 @@ def create_export_settings(self): group_box.setLayout(vbox) return group_box - def create_blacklist_layout(self): - blacklist_layout = QtGui.QVBoxLayout() + def create_blacklist_layout(self, blacklist_layout): self.tree_browser = TreeBrowser() + self.tree_browser.setContentsMargins(0, 0, 0, 0) + + self.blacklist_text = QtGui.QPlainTextEdit() + self.whitelist_text = QtGui.QPlainTextEdit() + + hlayout = QtGui.QHBoxLayout() + + blacklayout = QtGui.QVBoxLayout() + whitelayout = QtGui.QHBoxLayout() + blacklayout.addWidget(self.blacklist_text) + whitelayout.addWidget(self.whitelist_text) + + whitelist_setting = self.get_setting('whitelist') + blacklist_setting = self.get_setting('blacklist') + + self.blacklist_text.setStatusTip(blacklist_setting.description) + self.whitelist_text.setStatusTip(whitelist_setting.description) + + self.blacklist_text.setObjectName(blacklist_setting.name) + self.whitelist_text.setObjectName(whitelist_setting.name) + + blackgroup = QtGui.QGroupBox(blacklist_setting.display_name) + whitegroup = QtGui.QGroupBox(whitelist_setting.display_name) + + blackgroup.setLayout(blacklayout) + whitegroup.setLayout(whitelayout) + + blacklist_layout.addWidget(blackgroup) + blacklist_layout.addWidget(whitegroup) blacklist_layout.addWidget(self.tree_browser) + self.blacklist_text.textChanged.connect( + self.call_with_object('setting_changed', + self.blacklist_text, + blacklist_setting) + ) + + self.whitelist_text.textChanged.connect( + self.call_with_object('setting_changed', + self.whitelist_text, + whitelist_setting) + ) + + self.blacklist_text.textChanged.connect( + self.call_with_object('blacklist_changed', + self.blacklist_text, + blacklist_setting) + ) + + self.whitelist_text.textChanged.connect( + self.call_with_object('whitelist_changed', + self.whitelist_text, + whitelist_setting) + ) + return blacklist_layout + def blacklist_changed(self, text, blacklist_setting): + new_val = text.toPlainText() + output_blacklist = os.path.basename(self.output_dir()) + self.tree_browser.refresh(blacklist=(new_val.split('\n') + + ['*'+output_blacklist+'*'])) + + def whitelist_changed(self, text, whitelist_setting): + new_val = text.toPlainText() + self.tree_browser.refresh(whitelist=new_val.split('\n')) + + @property + def used_project_files(self): + return self.tree_browser.files + + @property + def used_project_dirs(self): + return self.tree_browser.dirs + def create_output_name_pattern_line(self): output_name_layout = QtGui.QHBoxLayout() @@ -1432,7 +1506,10 @@ def reset_settings(self): old_val = setting.default_value setting.value = old_val.replace('\\', '\\\\') - widget.setText(old_val) + if hasattr(widget, 'setText'): + widget.setText(old_val) + elif hasattr(widget, 'setPlainText'): + widget.setPlainText(old_val) elif setting.type == 'strings': old_val = [] if setting.default_value is not None: @@ -1494,7 +1571,11 @@ def setting_changed(self, obj, setting, *args): setting.type == 'file' or setting.type == 'folder' or setting.type == 'int'): - setting.value = args[0] + if args: + setting.value = args[0] + else: + setting.value = obj.toPlainText() + if not setting.value: setting.value = setting.default_value elif setting.type == 'strings': @@ -1646,7 +1727,10 @@ def load_package_json(self, json_path=None): setting.type == 'folder' or setting.type == 'int'): val_str = self.convert_val_to_str(setting.value) - setting_field.setText(setting.filter_name(val_str)) + if hasattr(setting_field, 'setText'): + setting_field.setText(setting.filter_name(val_str)) + elif hasattr(setting_field, 'setPlainText'): + setting_field.setPlainText(setting.filter_name(val_str)) if setting.type == 'strings': vals = [self.convert_val_to_str(v) for v in setting.value] setting_field.setText(','.join(vals)) diff --git a/util_classes.py b/util_classes.py index 82ffdcf..8eada17 100644 --- a/util_classes.py +++ b/util_classes.py @@ -2,8 +2,10 @@ import os import re +from fnmatch import fnmatch import zipfile import tarfile +import time import config import utils @@ -11,36 +13,31 @@ from PySide import QtGui, QtCore from PySide.QtCore import Qt + class FileItem(QtGui.QTreeWidgetItem): def __init__(self, parent=None, path=None): super(FileItem, self).__init__(parent) self.path = path -class TreeBrowser(QtGui.QWidget): - def __init__(self, directory=None, checked_files=None, - whitelist=None, blacklist=None, parent=None): - super(TreeBrowser, self).__init__(parent=parent) - self.root = QtGui.QTreeWidget() - self.root.setHeaderLabel('Included files') - self.root.itemChanged.connect(self.item_changed) - self.files = {} - self.paths = [] +class FileTree(object): + def __init__(self, directory=None, + whitelist=None, blacklist=None): - layout = QtGui.QVBoxLayout() - layout.addWidget(self.root) - self.setLayout(layout) + self.whitelist = None + self.blacklist = None - self.watcher = QtCore.QFileSystemWatcher() - self.watcher.directoryChanged.connect(self.directory_changed) - self.watcher.fileChanged.connect(self.file_changed) + self.paths = [] + self.walkcache = {} + self.cache = True + self.time = time.time() - self.directoryChanged = self.watcher.directoryChanged - self.fileChanged = self.watcher.fileChanged + self.files = [] + self.dirs = [] - self.init(directory, checked_files, whitelist, blacklist) + self.init(directory, whitelist, blacklist) - def init(self, directory=None, checked_files=None, + def init(self, directory=None, whitelist=None, blacklist=None): if directory: @@ -48,89 +45,215 @@ def init(self, directory=None, checked_files=None, else: self.directory = directory - self.checked_files = checked_files or [] + self.refresh(whitelist, blacklist) - self.whitelist = whitelist or [] - self.blacklist = blacklist or [] + def clear(self): + pass - self.watcher.removePaths(self.watcher.files()) + def refresh(self, whitelist=None, + blacklist=None): + self.whitelist = whitelist or self.whitelist or [] + self.blacklist = blacklist or self.blacklist or [] - self.files = {} + self.files = [] + self.dirs = [] - self.root.clear() + self.clear() - self.generate_directory_widget() + self.generate_files() - def file_changed(self, path): - print(path) - pass + def walk(self, directory): + refresh = False - def directory_changed(self, path): - print(path) - pass + if (time.time() - self.time) > 10: + refresh = True + self.time = time.time() - def get_abs_file_list(self): - return [os.path.join(self.directory, path) for path in self.files.keys()] + if not self.walkcache.get(directory) or refresh: + self.walkcache[directory] = [] + return os.walk(directory) - def get_checked_files(self): - pass + return self.walkcache[directory] - def item_changed(self, item, column): - self.files[item.path] = item.checkState(column) + def determine_skip(self, path): + skip = False - def generate_directory_widget(self): + for blacklist in self.blacklist: + match = fnmatch(path, blacklist) + if match: + skip = True + break + + for whitelist in self.whitelist: + match = fnmatch(path, whitelist) + if match: + skip = False + break + + return skip + + def init_cache(self): + if self.walkcache.get(self.directory) is None: + self.walkcache[self.directory] = [] + + self.cache = False + if not self.walkcache[self.directory]: + self.cache = True + + def add_to_cache(self, *args): + if self.cache: + self.walkcache[self.directory].append(args) + + def generate_files(self): if self.directory is None: return - parent_map = {'': self.root} + self.init_cache() + + for root, dirs, files in self.walk(self.directory): + self.add_to_cache(root, dirs, files) + + proj_path = root.replace(self.directory, '') - for root, dirs, files in os.walk(self.directory): for directory in dirs: + path = os.path.join(proj_path, directory) - proj_path = root.replace(self.directory, '') + if self.determine_skip(path): + continue - parent = parent_map[proj_path] + self.dirs.append(path) - path = os.path.join(proj_path, directory) + for file in files: + path = os.path.join(proj_path, file) - checked = Qt.Unchecked + if self.determine_skip(path): + continue - for checked_file in self.checked_files: - match = re.match('^'+checked_file, path) - if match: - checked = Qt.Checked + self.files.append(path) - child = FileItem(parent, path) - child.setFlags(child.flags() | Qt.ItemIsTristate | Qt.ItemIsUserCheckable) - child.setText(0, directory) - child.setCheckState(0, checked) - self.files[path] = checked +class TreeBrowser(QtGui.QWidget, FileTree): + def __init__(self, directory=None, + whitelist=None, blacklist=None, parent=None): + QtGui.QWidget.__init__(self, parent=parent) + self.root = QtGui.QTreeWidget() + self.root.header().setResizeMode(QtGui.QHeaderView.ResizeToContents) + self.root.header().setStretchLastSection(False) + self.root.setHeaderLabel('Included files') - parent_map[path] = child + self.parent_map = {} - for file in files: - proj_path = root.replace(self.directory, '') + layout = QtGui.QVBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) + layout.addWidget(self.root) + self.setLayout(layout) - parent = parent_map[proj_path] + FileTree.__init__(self, directory, whitelist, blacklist) - path = os.path.join(proj_path, file) + def clear(self): + self.root.clear() + + def fix_tree(self, path, parent): + temp = parent + tree = [] + root = None + base, direc = os.path.split(path) + new_path = os.path.join(base, direc) + + while new_path and root is None: + temp = self.parent_map.get(os.path.join(base, direc)) + if temp is not None: + root = temp + break + + child = FileItem(None, os.path.join(base, direc)) + child.setText(0, direc) + + tree.insert(0, child) + base, direc = os.path.split(base) + new_path = os.path.join(base, direc) + + self.parent_map[child.path] = child + + # if we reached the top of the directory chain + if root is None: + # if the path is still valid, that means we need to create + # a new top level item + if new_path: + root = FileItem(None, new_path) + root.setText(0, direc) + self.parent_map[root.path] = root + else: + # otherwise, the if the path is empty, we already + # have a top level item, so use that + root = tree.pop(0) + + self.root.addTopLevelItem(root) + + # add all the children to the root node + temp = root + for child in tree: + temp.addChild(child) + temp = child + + def determine_skip(self, path, parent): + skip = False + + for blacklist in self.blacklist: + match = fnmatch(path, blacklist) + if match: + skip = True + break + + for whitelist in self.whitelist: + match = fnmatch(path, whitelist) + if match: + skip = False + if parent is None: + self.fix_tree(path, parent) + break + + return skip + + def generate_files(self): + if self.directory is None: + return + + self.parent_map = {'': self.root} + + self.init_cache() - checked = Qt.Unchecked + for root, dirs, files in self.walk(self.directory): + self.add_to_cache(root, dirs, files) - for checked_file in self.checked_files: - match = re.match(checked_file, path) - if match: - checked = Qt.Checked + proj_path = root.replace(self.directory, '') + + for directory in dirs: + parent = self.parent_map.get(proj_path) + + path = os.path.join(proj_path, directory) + + if self.determine_skip(path, parent) or parent is None: + continue child = FileItem(parent, path) - child.setFlags(child.flags() | Qt.ItemIsUserCheckable) - child.setText(0, file) - child.setCheckState(0, checked) + child.setText(0, directory) + self.parent_map[path] = child + self.dirs.append(path) - self.files[path] = checked + for file in files: + parent = self.parent_map.get(proj_path) + + path = os.path.join(proj_path, file) + + if self.determine_skip(path, parent) or parent is None: + continue + + child = FileItem(parent, path) + child.setText(0, file) + self.files.append(path) - self.watcher.addPaths(self.get_abs_file_list()) + self.root.sortItems(0, Qt.AscendingOrder) class ExistingProjectDialog(QtGui.QDialog): diff --git a/utils.py b/utils.py index b5ef0d1..aa9158c 100644 --- a/utils.py +++ b/utils.py @@ -15,6 +15,7 @@ import subprocess from appdirs import AppDirs import validators +import traceback from PySide import QtCore @@ -206,7 +207,7 @@ def open_folder_in_explorer(path): else: subprocess.Popen(["xdg-open", path]) -def zip_files(zip_file_name, *args, **kwargs): +def zip_files(zip_file_name, project_dir, *args, **kwargs): """ Zip files into an archive programmatically. @@ -222,14 +223,13 @@ def zip_files(zip_file_name, *args, **kwargs): exclude_paths = kwargs.pop('exclude_paths', []) old_path = os.getcwd() + os.chdir(project_dir) + for arg in args: if is_windows(): arg = '\\\\?\\'+os.path.abspath(arg).replace('/', '\\') if os.path.exists(arg): if os.path.isdir(arg): - directory = os.path.abspath(arg) - os.chdir(directory) - for root, dirs, files in os.walk(directory): excluded = False for exclude_path in exclude_paths: @@ -260,10 +260,7 @@ def zip_files(zip_file_name, *args, **kwargs): pass else: - file = os.path.abspath(arg) - directory = os.path.abspath(path_join(file, '..')) - os.chdir(directory) - file_loc = os.path.relpath(arg, directory) + file_loc = arg if verbose: log(file_loc) try: