mirror of
https://github.com/arsenetar/dupeguru.git
synced 2026-01-25 16:11:39 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19beb919d0 | ||
|
|
ba09e8bf4d | ||
|
|
26dd2d0e8e | ||
|
|
69b15d58a2 | ||
|
|
ba68789fb9 | ||
|
|
47a6ceffbc | ||
|
|
b17ca66f73 | ||
|
|
93bc609026 | ||
|
|
3ea51c2e15 |
1
.hgtags
1
.hgtags
@@ -12,3 +12,4 @@ cbcf9c80fee4c908ef2efbf1c143c9e47676c9b2 pe1.8.0
|
|||||||
7b7c5a66ebee4e4b8125330d24fe9ce1a070ff25 se2.9.2
|
7b7c5a66ebee4e4b8125330d24fe9ce1a070ff25 se2.9.2
|
||||||
1cef6d39855f85d4be728646bc78b860e6d4e398 pe1.8.3
|
1cef6d39855f85d4be728646bc78b860e6d4e398 pe1.8.3
|
||||||
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
90ed56ee602666db2f267f73eac6f824347039b5 me5.7.2
|
||||||
|
4c3cb1e671a333eabde1151c7c6ffb3609cab025 pe1.8.4
|
||||||
|
|||||||
1
README
1
README
@@ -27,6 +27,7 @@ General dependencies
|
|||||||
-----
|
-----
|
||||||
|
|
||||||
- Python 2.6 (http://www.python.org)
|
- Python 2.6 (http://www.python.org)
|
||||||
|
- lxml, to read and write XML files. (http://codespeak.net/lxml/)
|
||||||
- Mako, to generate help files. (http://www.makotemplates.org/)
|
- Mako, to generate help files. (http://www.makotemplates.org/)
|
||||||
- PyYaml, for help files and the build system. (http://pyyaml.org/)
|
- PyYaml, for help files and the build system. (http://pyyaml.org/)
|
||||||
- Nose, to run unit tests. (http://somethingaboutorange.com/mrl/projects/nose/)
|
- Nose, to run unit tests. (http://somethingaboutorange.com/mrl/projects/nose/)
|
||||||
|
|||||||
@@ -11,9 +11,11 @@ from core_me.app_cocoa import DupeGuruME
|
|||||||
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
|
from core.scanner import (SCAN_TYPE_FILENAME, SCAN_TYPE_FIELDS, SCAN_TYPE_FIELDS_NO_ORDER,
|
||||||
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)
|
SCAN_TYPE_TAG, SCAN_TYPE_CONTENT, SCAN_TYPE_CONTENT_AUDIO)
|
||||||
|
|
||||||
# Fix py2app imports which chokes on relative imports
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
from core_me import app_cocoa, data, fs, scanner
|
from core_me import app_cocoa, data, fs, scanner
|
||||||
from hsmedia import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
from hsmedia import aiff, flac, genres, id3v1, id3v2, mp4, mpeg, ogg, wma
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||||
<data>
|
<data>
|
||||||
<int key="IBDocument.SystemTarget">1050</int>
|
<int key="IBDocument.SystemTarget">1050</int>
|
||||||
<string key="IBDocument.SystemVersion">10B504</string>
|
<string key="IBDocument.SystemVersion">10C540</string>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.2</string>
|
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">437.00</string>
|
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string key="NS.object.0">740</string>
|
<string key="NS.object.0">740</string>
|
||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="579641073">
|
<object class="NSUserDefaultsController" id="579641073">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="793317856">
|
<object class="NSWindowTemplate" id="793317856">
|
||||||
@@ -552,7 +556,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="58676792">
|
<object class="NSButtonCell" key="NSCell" id="58676792">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="147113892"/>
|
<reference key="NSControlView" ref="147113892"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -980,22 +984,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">84</int>
|
<int key="connectionID">84</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="147113892"/>
|
|
||||||
<reference key="destination" ref="579641073"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="147113892"/>
|
|
||||||
<reference key="NSDestination" ref="579641073"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">85</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">nextKeyView</string>
|
<string key="label">nextKeyView</string>
|
||||||
@@ -1348,6 +1336,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">113</int>
|
<int key="connectionID">113</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="147113892"/>
|
||||||
|
<reference key="destination" ref="579641073"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="147113892"/>
|
||||||
|
<reference key="NSDestination" ref="579641073"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">114</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1838,8 +1842,6 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="NSArray" key="dict.sortedKeys">
|
<object class="NSArray" key="dict.sortedKeys">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string>-1.IBPluginDependency</string>
|
|
||||||
<string>-2.IBPluginDependency</string>
|
|
||||||
<string>-3.IBPluginDependency</string>
|
<string>-3.IBPluginDependency</string>
|
||||||
<string>1.IBPluginDependency</string>
|
<string>1.IBPluginDependency</string>
|
||||||
<string>1.ImportedFromIB2</string>
|
<string>1.ImportedFromIB2</string>
|
||||||
@@ -1949,8 +1951,6 @@
|
|||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<boolean value="YES"/>
|
<boolean value="YES"/>
|
||||||
@@ -2071,9 +2071,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">113</int>
|
<int key="maxID">114</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>hsft</string>
|
<string>hsft</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1.8.4</string>
|
<string>1.8.5</string>
|
||||||
<key>NSMainNibFile</key>
|
<key>NSMainNibFile</key>
|
||||||
<string>MainMenu</string>
|
<string>MainMenu</string>
|
||||||
<key>NSPrincipalClass</key>
|
<key>NSPrincipalClass</key>
|
||||||
|
|||||||
@@ -7,8 +7,10 @@
|
|||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
from core_pe import app_cocoa as app_pe_cocoa
|
from core_pe import app_cocoa as app_pe_cocoa
|
||||||
|
|
||||||
# Fix py2app imports which chokes on relative imports
|
# Fix py2app imports which chokes on relative imports and other stuff
|
||||||
from core_pe import block, cache, matchbase, data, _block_osx
|
from core_pe import block, cache, matchbase, data, _block_osx
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -2,17 +2,17 @@
|
|||||||
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
|
||||||
<data>
|
<data>
|
||||||
<int key="IBDocument.SystemTarget">1050</int>
|
<int key="IBDocument.SystemTarget">1050</int>
|
||||||
<string key="IBDocument.SystemVersion">10B504</string>
|
<string key="IBDocument.SystemVersion">10C540</string>
|
||||||
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
<string key="IBDocument.InterfaceBuilderVersion">740</string>
|
||||||
<string key="IBDocument.AppKitVersion">1038.2</string>
|
<string key="IBDocument.AppKitVersion">1038.25</string>
|
||||||
<string key="IBDocument.HIToolboxVersion">437.00</string>
|
<string key="IBDocument.HIToolboxVersion">458.00</string>
|
||||||
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
|
||||||
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
|
||||||
<string key="NS.object.0">740</string>
|
<string key="NS.object.0">740</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<integer value="2"/>
|
<integer value="3"/>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSArray" key="IBDocument.PluginDependencies">
|
<object class="NSArray" key="IBDocument.PluginDependencies">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="455472712">
|
<object class="NSUserDefaultsController" id="455472712">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="809668081">
|
<object class="NSWindowTemplate" id="809668081">
|
||||||
@@ -411,7 +415,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="2297113">
|
<object class="NSButtonCell" key="NSCell" id="2297113">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="472028782"/>
|
<reference key="NSControlView" ref="472028782"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -541,22 +545,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">39</int>
|
<int key="connectionID">39</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="472028782"/>
|
|
||||||
<reference key="destination" ref="455472712"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="472028782"/>
|
|
||||||
<reference key="NSDestination" ref="455472712"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">40</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBActionConnection" key="connection">
|
<object class="IBActionConnection" key="connection">
|
||||||
<string key="label">revertToInitialValues:</string>
|
<string key="label">revertToInitialValues:</string>
|
||||||
@@ -677,6 +665,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">51</int>
|
<int key="connectionID">51</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="472028782"/>
|
||||||
|
<reference key="destination" ref="455472712"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="472028782"/>
|
||||||
|
<reference key="NSDestination" ref="455472712"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">58</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1110,9 +1114,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">51</int>
|
<int key="maxID">58</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
#import "../../cocoalib/Outline.h"
|
|
||||||
#import "../base/ResultWindow.h"
|
#import "../base/ResultWindow.h"
|
||||||
#import "DirectoryPanel.h"
|
#import "DirectoryPanel.h"
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ http://www.hardcoded.net/licenses/hs_license
|
|||||||
- (void)awakeFromNib
|
- (void)awakeFromNib
|
||||||
{
|
{
|
||||||
[super awakeFromNib];
|
[super awakeFromNib];
|
||||||
_deltaColumns = [[NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,4)] retain];
|
NSMutableIndexSet *deltaColumns = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(2,4)];
|
||||||
[_deltaColumns removeIndex:3];
|
[deltaColumns removeIndex:3];
|
||||||
|
[outline setDeltaColumns:deltaColumns];
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Actions */
|
/* Actions */
|
||||||
|
|||||||
@@ -10,8 +10,10 @@ from core import scanner
|
|||||||
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
from core.app_cocoa_inter import PyDupeGuruBase, PyDetailsPanel
|
||||||
from core_se.app_cocoa import DupeGuru
|
from core_se.app_cocoa import DupeGuru
|
||||||
|
|
||||||
# Fix py2app imports with chokes on relative imports
|
# Fix py2app imports with chokes on relative imports and other stuff
|
||||||
from core_se import fs, data
|
from core_se import fs, data
|
||||||
|
from lxml import etree, _elementpath
|
||||||
|
import gzip
|
||||||
|
|
||||||
class PyDupeGuru(PyDupeGuruBase):
|
class PyDupeGuru(PyDupeGuruBase):
|
||||||
def init(self):
|
def init(self):
|
||||||
|
|||||||
@@ -27,6 +27,8 @@
|
|||||||
CE76FDD4111EE3A7006618EA /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */; };
|
CE76FDD4111EE3A7006618EA /* DirectoryOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */; };
|
||||||
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
|
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDDE111EE42F006618EA /* HSOutline.m */; };
|
||||||
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.m */; };
|
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = CE76FDF6111EE561006618EA /* NSEventAdditions.m */; };
|
||||||
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F212113BC22D0010360B /* ResultOutline.m */; };
|
||||||
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = CE91F214113BC22D0010360B /* StatsLabel.m */; };
|
||||||
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
CEAC6811109B0B7E00B43C85 /* Preferences.xib in Resources */ = {isa = PBXBuildFile; fileRef = CEAC6810109B0B7E00B43C85 /* Preferences.xib */; };
|
||||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */; };
|
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */; };
|
||||||
CEDD92DA0FDD01640031C7B7 /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */; };
|
CEDD92DA0FDD01640031C7B7 /* BRSingleLineFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = CEDD92D70FDD01640031C7B7 /* BRSingleLineFormatter.m */; };
|
||||||
@@ -39,7 +41,6 @@
|
|||||||
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
CEFC295609C89FF200D9F998 /* preferences32.png in Resources */ = {isa = PBXBuildFile; fileRef = CEFC295409C89FF200D9F998 /* preferences32.png */; };
|
||||||
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8B0FC9517500CD5728 /* Dialogs.m */; };
|
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8B0FC9517500CD5728 /* Dialogs.m */; };
|
||||||
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */; };
|
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */; };
|
||||||
CEFC7FA00FC9517500CD5728 /* Outline.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F8F0FC9517500CD5728 /* Outline.m */; };
|
|
||||||
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F910FC9517500CD5728 /* ProgressController.m */; };
|
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F910FC9517500CD5728 /* ProgressController.m */; };
|
||||||
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F950FC9517500CD5728 /* RecentDirectories.m */; };
|
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F950FC9517500CD5728 /* RecentDirectories.m */; };
|
||||||
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F970FC9517500CD5728 /* RegistrationInterface.m */; };
|
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */ = {isa = PBXBuildFile; fileRef = CEFC7F970FC9517500CD5728 /* RegistrationInterface.m */; };
|
||||||
@@ -101,6 +102,12 @@
|
|||||||
CE76FDDE111EE42F006618EA /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
CE76FDDE111EE42F006618EA /* HSOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSOutline.m; sourceTree = "<group>"; };
|
||||||
CE76FDF5111EE561006618EA /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
CE76FDF5111EE561006618EA /* NSEventAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NSEventAdditions.h; path = ../../cocoalib/NSEventAdditions.h; sourceTree = SOURCE_ROOT; };
|
||||||
CE76FDF6111EE561006618EA /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
CE76FDF6111EE561006618EA /* NSEventAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NSEventAdditions.m; path = ../../cocoalib/NSEventAdditions.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F20F113BC22D0010360B /* PyResultTree.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyResultTree.h; path = ../base/PyResultTree.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F210113BC22D0010360B /* PyStatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyStatsLabel.h; path = ../base/PyStatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F211113BC22D0010360B /* ResultOutline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ResultOutline.h; path = ../base/ResultOutline.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F212113BC22D0010360B /* ResultOutline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ResultOutline.m; path = ../base/ResultOutline.m; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F213113BC22D0010360B /* StatsLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StatsLabel.h; path = ../base/StatsLabel.h; sourceTree = SOURCE_ROOT; };
|
||||||
|
CE91F214113BC22D0010360B /* StatsLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = StatsLabel.m; path = ../base/StatsLabel.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
|
CEAC6810109B0B7E00B43C85 /* Preferences.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Preferences.xib; path = xib/Preferences.xib; sourceTree = "<group>"; };
|
||||||
CEBE4D72111F0EE1009AAC6D /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
CEBE4D72111F0EE1009AAC6D /* HSWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HSWindowController.h; sourceTree = "<group>"; };
|
||||||
CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
CEBE4D73111F0EE1009AAC6D /* HSWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HSWindowController.m; sourceTree = "<group>"; };
|
||||||
@@ -118,8 +125,6 @@
|
|||||||
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Dialogs.m; path = ../../cocoalib/Dialogs.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HSErrorReportWindow.h; path = ../../cocoalib/HSErrorReportWindow.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HSErrorReportWindow.m; path = ../../cocoalib/HSErrorReportWindow.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F8E0FC9517500CD5728 /* Outline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Outline.h; path = ../../cocoalib/Outline.h; sourceTree = SOURCE_ROOT; };
|
|
||||||
CEFC7F8F0FC9517500CD5728 /* Outline.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Outline.m; path = ../../cocoalib/Outline.m; sourceTree = SOURCE_ROOT; };
|
|
||||||
CEFC7F900FC9517500CD5728 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F900FC9517500CD5728 /* ProgressController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ProgressController.h; path = ../../cocoalib/ProgressController.h; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F910FC9517500CD5728 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
CEFC7F910FC9517500CD5728 /* ProgressController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ProgressController.m; path = ../../cocoalib/ProgressController.m; sourceTree = SOURCE_ROOT; };
|
||||||
CEFC7F920FC9517500CD5728 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
CEFC7F920FC9517500CD5728 /* PyApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PyApp.h; path = ../../cocoalib/PyApp.h; sourceTree = SOURCE_ROOT; };
|
||||||
@@ -326,8 +331,6 @@
|
|||||||
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */,
|
CEFC7F8B0FC9517500CD5728 /* Dialogs.m */,
|
||||||
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */,
|
CEFC7F8C0FC9517500CD5728 /* HSErrorReportWindow.h */,
|
||||||
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */,
|
CEFC7F8D0FC9517500CD5728 /* HSErrorReportWindow.m */,
|
||||||
CEFC7F8E0FC9517500CD5728 /* Outline.h */,
|
|
||||||
CEFC7F8F0FC9517500CD5728 /* Outline.m */,
|
|
||||||
CEFC7F900FC9517500CD5728 /* ProgressController.h */,
|
CEFC7F900FC9517500CD5728 /* ProgressController.h */,
|
||||||
CEFC7F910FC9517500CD5728 /* ProgressController.m */,
|
CEFC7F910FC9517500CD5728 /* ProgressController.m */,
|
||||||
CEFC7F920FC9517500CD5728 /* PyApp.h */,
|
CEFC7F920FC9517500CD5728 /* PyApp.h */,
|
||||||
@@ -347,6 +350,12 @@
|
|||||||
CEFC7FB00FC9518F00CD5728 /* dgbase */ = {
|
CEFC7FB00FC9518F00CD5728 /* dgbase */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
CE91F20F113BC22D0010360B /* PyResultTree.h */,
|
||||||
|
CE91F210113BC22D0010360B /* PyStatsLabel.h */,
|
||||||
|
CE91F211113BC22D0010360B /* ResultOutline.h */,
|
||||||
|
CE91F212113BC22D0010360B /* ResultOutline.m */,
|
||||||
|
CE91F213113BC22D0010360B /* StatsLabel.h */,
|
||||||
|
CE91F214113BC22D0010360B /* StatsLabel.m */,
|
||||||
CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */,
|
CE76FDD1111EE3A7006618EA /* DirectoryOutline.h */,
|
||||||
CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */,
|
CE76FDD2111EE3A7006618EA /* DirectoryOutline.m */,
|
||||||
CE76FDD3111EE3A7006618EA /* PyDirectoryOutline.h */,
|
CE76FDD3111EE3A7006618EA /* PyDirectoryOutline.h */,
|
||||||
@@ -441,7 +450,6 @@
|
|||||||
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
CE381C9C09914ADF003581CE /* ResultWindow.m in Sources */,
|
||||||
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */,
|
CEFC7F9E0FC9517500CD5728 /* Dialogs.m in Sources */,
|
||||||
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */,
|
CEFC7F9F0FC9517500CD5728 /* HSErrorReportWindow.m in Sources */,
|
||||||
CEFC7FA00FC9517500CD5728 /* Outline.m in Sources */,
|
|
||||||
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */,
|
CEFC7FA10FC9517500CD5728 /* ProgressController.m in Sources */,
|
||||||
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */,
|
CEFC7FA20FC9517500CD5728 /* RecentDirectories.m in Sources */,
|
||||||
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */,
|
CEFC7FA30FC9517500CD5728 /* RegistrationInterface.m in Sources */,
|
||||||
@@ -460,6 +468,8 @@
|
|||||||
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */,
|
CE76FDDF111EE42F006618EA /* HSOutline.m in Sources */,
|
||||||
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */,
|
CE76FDF7111EE561006618EA /* NSEventAdditions.m in Sources */,
|
||||||
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
CEBE4D74111F0EE1009AAC6D /* HSWindowController.m in Sources */,
|
||||||
|
CE91F215113BC22D0010360B /* ResultOutline.m in Sources */,
|
||||||
|
CE91F216113BC22D0010360B /* StatsLabel.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -39,6 +39,10 @@
|
|||||||
<string key="NSClassName">NSApplication</string>
|
<string key="NSClassName">NSApplication</string>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSUserDefaultsController" id="75941798">
|
<object class="NSUserDefaultsController" id="75941798">
|
||||||
|
<object class="NSMutableArray" key="NSDeclaredKeys">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<string>SUEnableAutomaticChecks</string>
|
||||||
|
</object>
|
||||||
<bool key="NSSharedInstance">YES</bool>
|
<bool key="NSSharedInstance">YES</bool>
|
||||||
</object>
|
</object>
|
||||||
<object class="NSWindowTemplate" id="489014306">
|
<object class="NSWindowTemplate" id="489014306">
|
||||||
@@ -507,7 +511,7 @@
|
|||||||
<object class="NSButtonCell" key="NSCell" id="456303302">
|
<object class="NSButtonCell" key="NSCell" id="456303302">
|
||||||
<int key="NSCellFlags">67239424</int>
|
<int key="NSCellFlags">67239424</int>
|
||||||
<int key="NSCellFlags2">0</int>
|
<int key="NSCellFlags2">0</int>
|
||||||
<string key="NSContents">Check for update on startup</string>
|
<string key="NSContents">Automatically check for updates</string>
|
||||||
<reference key="NSSupport" ref="26"/>
|
<reference key="NSSupport" ref="26"/>
|
||||||
<reference key="NSControlView" ref="551239185"/>
|
<reference key="NSControlView" ref="551239185"/>
|
||||||
<int key="NSButtonFlags">1211912703</int>
|
<int key="NSButtonFlags">1211912703</int>
|
||||||
@@ -844,22 +848,6 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">110</int>
|
<int key="connectionID">110</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
|
||||||
<object class="IBBindingConnection" key="connection">
|
|
||||||
<string key="label">value: values.SUCheckAtStartup</string>
|
|
||||||
<reference key="source" ref="551239185"/>
|
|
||||||
<reference key="destination" ref="75941798"/>
|
|
||||||
<object class="NSNibBindingConnector" key="connector">
|
|
||||||
<reference key="NSSource" ref="551239185"/>
|
|
||||||
<reference key="NSDestination" ref="75941798"/>
|
|
||||||
<string key="NSLabel">value: values.SUCheckAtStartup</string>
|
|
||||||
<string key="NSBinding">value</string>
|
|
||||||
<string key="NSKeyPath">values.SUCheckAtStartup</string>
|
|
||||||
<int key="NSNibBindingConnectorVersion">2</int>
|
|
||||||
</object>
|
|
||||||
</object>
|
|
||||||
<int key="connectionID">111</int>
|
|
||||||
</object>
|
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBBindingConnection" key="connection">
|
<object class="IBBindingConnection" key="connection">
|
||||||
<string key="label">value: values.removeEmptyFolders</string>
|
<string key="label">value: values.removeEmptyFolders</string>
|
||||||
@@ -972,6 +960,22 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">121</int>
|
<int key="connectionID">121</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBBindingConnection" key="connection">
|
||||||
|
<string key="label">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<reference key="source" ref="551239185"/>
|
||||||
|
<reference key="destination" ref="75941798"/>
|
||||||
|
<object class="NSNibBindingConnector" key="connector">
|
||||||
|
<reference key="NSSource" ref="551239185"/>
|
||||||
|
<reference key="NSDestination" ref="75941798"/>
|
||||||
|
<string key="NSLabel">value: values.SUEnableAutomaticChecks</string>
|
||||||
|
<string key="NSBinding">value</string>
|
||||||
|
<string key="NSKeyPath">values.SUEnableAutomaticChecks</string>
|
||||||
|
<int key="NSNibBindingConnectorVersion">2</int>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">122</int>
|
||||||
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<object class="NSArray" key="orderedObjects">
|
<object class="NSArray" key="orderedObjects">
|
||||||
@@ -1582,9 +1586,26 @@
|
|||||||
</object>
|
</object>
|
||||||
</object>
|
</object>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">121</int>
|
<int key="maxID">122</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
|
<object class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/HSOutlineView.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
<object class="IBPartialClassDescription">
|
||||||
|
<string key="className">NSObject</string>
|
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier">
|
||||||
|
<string key="majorKey">IBProjectSource</string>
|
||||||
|
<string key="minorKey">../views/NSTableViewAdditions.h</string>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
|
</object>
|
||||||
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
<object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
|
||||||
<bool key="EncodedWithXMLCoder">YES</bool>
|
<bool key="EncodedWithXMLCoder">YES</bool>
|
||||||
<object class="IBPartialClassDescription">
|
<object class="IBPartialClassDescription">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import xml.dom.minidom
|
from lxml import etree
|
||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
from hsutil.files import FileOrPath
|
from hsutil.files import FileOrPath
|
||||||
@@ -126,38 +126,38 @@ class Directories(object):
|
|||||||
|
|
||||||
def load_from_file(self, infile):
|
def load_from_file(self, infile):
|
||||||
try:
|
try:
|
||||||
doc = xml.dom.minidom.parse(infile)
|
root = etree.parse(infile).getroot()
|
||||||
except:
|
except:
|
||||||
return
|
return
|
||||||
root_path_nodes = doc.getElementsByTagName('root_directory')
|
for rdn in root.iterchildren('root_directory'):
|
||||||
for rdn in root_path_nodes:
|
attrib = rdn.attrib
|
||||||
if not rdn.getAttributeNode('path'):
|
if 'path' not in attrib:
|
||||||
continue
|
continue
|
||||||
path = rdn.getAttributeNode('path').nodeValue
|
path = attrib['path']
|
||||||
try:
|
try:
|
||||||
self.add_path(Path(path))
|
self.add_path(Path(path))
|
||||||
except (AlreadyThereError, InvalidPathError):
|
except (AlreadyThereError, InvalidPathError):
|
||||||
pass
|
pass
|
||||||
state_nodes = doc.getElementsByTagName('state')
|
for sn in root.iterchildren('state'):
|
||||||
for sn in state_nodes:
|
attrib = sn.attrib
|
||||||
if not (sn.getAttributeNode('path') and sn.getAttributeNode('value')):
|
if not ('path' in attrib and 'value' in attrib):
|
||||||
continue
|
continue
|
||||||
path = sn.getAttributeNode('path').nodeValue
|
path = attrib['path']
|
||||||
state = sn.getAttributeNode('value').nodeValue
|
state = attrib['value']
|
||||||
self.set_state(Path(path), int(state))
|
self.set_state(Path(path), int(state))
|
||||||
|
|
||||||
def save_to_file(self, outfile):
|
def save_to_file(self, outfile):
|
||||||
with FileOrPath(outfile, 'wb') as fp:
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('directories')
|
||||||
root = doc.appendChild(doc.createElement('directories'))
|
|
||||||
for root_path in self:
|
for root_path in self:
|
||||||
root_path_node = root.appendChild(doc.createElement('root_directory'))
|
root_path_node = etree.SubElement(root, 'root_directory')
|
||||||
root_path_node.setAttribute('path', unicode(root_path).encode('utf-8'))
|
root_path_node.set('path', unicode(root_path))
|
||||||
for path, state in self.states.iteritems():
|
for path, state in self.states.iteritems():
|
||||||
state_node = root.appendChild(doc.createElement('state'))
|
state_node = etree.SubElement(root, 'state')
|
||||||
state_node.setAttribute('path', unicode(path).encode('utf-8'))
|
state_node.set('path', unicode(path))
|
||||||
state_node.setAttribute('value', str(state))
|
state_node.set('value', unicode(state))
|
||||||
doc.writexml(fp, '\t', '\t', '\n', encoding='utf-8')
|
tree = etree.ElementTree(root)
|
||||||
|
tree.write(fp, encoding='utf-8')
|
||||||
|
|
||||||
def set_state(self, path, state):
|
def set_state(self, path, state):
|
||||||
if self.get_state(path) == state:
|
if self.get_state(path) == state:
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
from hsutil.files import FileOrPath
|
from lxml import etree
|
||||||
|
|
||||||
import xml.dom.minidom
|
from hsutil.files import FileOrPath
|
||||||
|
|
||||||
class IgnoreList(object):
|
class IgnoreList(object):
|
||||||
"""An ignore list implementation that is iterable, filterable and exportable to XML.
|
"""An ignore list implementation that is iterable, filterable and exportable to XML.
|
||||||
@@ -77,19 +77,16 @@ class IgnoreList(object):
|
|||||||
infile can be a file object or a filename.
|
infile can be a file object or a filename.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
doc = xml.dom.minidom.parse(infile)
|
root = etree.parse(infile).getroot()
|
||||||
except Exception:
|
except Exception:
|
||||||
return
|
return
|
||||||
file_nodes = doc.getElementsByTagName('file')
|
for fn in root.iterchildren('file'):
|
||||||
for fn in file_nodes:
|
file_path = fn.get('path')
|
||||||
if not fn.getAttributeNode('path'):
|
if not file_path:
|
||||||
continue
|
continue
|
||||||
file_path = fn.getAttributeNode('path').nodeValue
|
for sfn in fn.iterchildren('file'):
|
||||||
subfile_nodes = fn.getElementsByTagName('file')
|
subfile_path = sfn.get('path')
|
||||||
for sfn in subfile_nodes:
|
if subfile_path:
|
||||||
if not sfn.getAttributeNode('path'):
|
|
||||||
continue
|
|
||||||
subfile_path = sfn.getAttributeNode('path').nodeValue
|
|
||||||
self.Ignore(file_path, subfile_path)
|
self.Ignore(file_path, subfile_path)
|
||||||
|
|
||||||
def save_to_xml(self, outfile):
|
def save_to_xml(self, outfile):
|
||||||
@@ -97,19 +94,15 @@ class IgnoreList(object):
|
|||||||
|
|
||||||
outfile can be a file object or a filename.
|
outfile can be a file object or a filename.
|
||||||
"""
|
"""
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('ignore_list')
|
||||||
root = doc.appendChild(doc.createElement('ignore_list'))
|
for filename, subfiles in self._ignored.items():
|
||||||
for file,subfiles in self._ignored.items():
|
file_node = etree.SubElement(root, 'file')
|
||||||
file_node = root.appendChild(doc.createElement('file'))
|
file_node.set('path', filename)
|
||||||
if isinstance(file,unicode):
|
for subfilename in subfiles:
|
||||||
file = file.encode('utf-8')
|
subfile_node = etree.SubElement(file_node, 'file')
|
||||||
file_node.setAttribute('path',file)
|
subfile_node.set('path', subfilename)
|
||||||
for subfile in subfiles:
|
tree = etree.ElementTree(root)
|
||||||
subfile_node = file_node.appendChild(doc.createElement('file'))
|
|
||||||
if isinstance(subfile,unicode):
|
|
||||||
subfile = subfile.encode('utf-8')
|
|
||||||
subfile_node.setAttribute('path',subfile)
|
|
||||||
with FileOrPath(outfile, 'wb') as fp:
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
doc.writexml(fp,'\t','\t','\n',encoding='utf-8')
|
tree.write(fp, encoding='utf-8')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
180
core/results.py
180
core/results.py
@@ -8,16 +8,14 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from xml.sax import handler, make_parser, SAXException
|
from lxml import etree
|
||||||
from xml.sax.saxutils import XMLGenerator
|
|
||||||
from xml.sax.xmlreader import AttributesImpl
|
|
||||||
|
|
||||||
from . import engine
|
from . import engine
|
||||||
from hsutil.job import nulljob
|
from hsutil.job import nulljob
|
||||||
from hsutil.markable import Markable
|
from hsutil.markable import Markable
|
||||||
from hsutil.misc import flatten, cond, nonone
|
from hsutil.misc import flatten, nonone
|
||||||
from hsutil.str import format_size
|
from hsutil.str import format_size
|
||||||
from hsutil.files import open_if_filename
|
from hsutil.files import FileOrPath
|
||||||
|
|
||||||
class Results(Markable):
|
class Results(Markable):
|
||||||
#---Override
|
#---Override
|
||||||
@@ -168,42 +166,54 @@ class Results(Markable):
|
|||||||
is_markable = _is_markable
|
is_markable = _is_markable
|
||||||
|
|
||||||
def load_from_xml(self, infile, get_file, j=nulljob):
|
def load_from_xml(self, infile, get_file, j=nulljob):
|
||||||
|
def do_match(ref_file, other_files, group):
|
||||||
|
if not other_files:
|
||||||
|
return
|
||||||
|
for other_file in other_files:
|
||||||
|
group.add_match(engine.get_match(ref_file, other_file))
|
||||||
|
do_match(other_files[0], other_files[1:], group)
|
||||||
|
|
||||||
self.apply_filter(None)
|
self.apply_filter(None)
|
||||||
handler = _ResultsHandler(get_file)
|
|
||||||
try:
|
try:
|
||||||
parser = make_parser()
|
root = etree.parse(infile).getroot()
|
||||||
except Exception as e:
|
except Exception:
|
||||||
# This special handling is to try to figure out the cause of #47
|
|
||||||
# We don't silently return, because we want the user to send error report.
|
|
||||||
logging.exception(e)
|
|
||||||
try:
|
|
||||||
import xml.parsers.expat
|
|
||||||
logging.warning('importing xml.parsers.expat went ok, WTF?')
|
|
||||||
except Exception as e:
|
|
||||||
# This log should give a little more details about the cause of this all
|
|
||||||
logging.exception(e)
|
|
||||||
raise
|
|
||||||
raise
|
|
||||||
parser.setContentHandler(handler)
|
|
||||||
try:
|
|
||||||
infile, must_close = open_if_filename(infile)
|
|
||||||
except IOError:
|
|
||||||
return
|
return
|
||||||
BUFSIZE = 1024 * 1024 # 1mb buffer
|
group_elems = list(root.iterchildren('group'))
|
||||||
infile.seek(0, 2)
|
groups = []
|
||||||
j.start_job(infile.tell() // BUFSIZE)
|
marked = set()
|
||||||
infile.seek(0, 0)
|
for group_elem in j.iter_with_progress(group_elems, every=100):
|
||||||
|
group = engine.Group()
|
||||||
|
dupes = []
|
||||||
|
for file_elem in group_elem.iterchildren('file'):
|
||||||
|
path = file_elem.get('path')
|
||||||
|
words = file_elem.get('words', '')
|
||||||
|
if not path:
|
||||||
|
continue
|
||||||
|
file = get_file(path)
|
||||||
|
if file is None:
|
||||||
|
continue
|
||||||
|
file.words = words.split(',')
|
||||||
|
file.is_ref = file_elem.get('is_ref') == 'y'
|
||||||
|
dupes.append(file)
|
||||||
|
if file_elem.get('marked') == 'y':
|
||||||
|
marked.add(file)
|
||||||
|
for match_elem in group_elem.iterchildren('match'):
|
||||||
try:
|
try:
|
||||||
while True:
|
attrs = match_elem.attrib
|
||||||
data = infile.read(BUFSIZE)
|
first_file = dupes[int(attrs['first'])]
|
||||||
if not data:
|
second_file = dupes[int(attrs['second'])]
|
||||||
break
|
percentage = int(attrs['percentage'])
|
||||||
parser.feed(data)
|
group.add_match(engine.Match(first_file, second_file, percentage))
|
||||||
|
except (IndexError, KeyError, ValueError): # Covers missing attr, non-int values and indexes out of bounds
|
||||||
|
pass
|
||||||
|
if (not group.matches) and (len(dupes) >= 2):
|
||||||
|
do_match(dupes[0], dupes[1:], group)
|
||||||
|
group.prioritize(lambda x: dupes.index(x))
|
||||||
|
if len(group):
|
||||||
|
groups.append(group)
|
||||||
j.add_progress()
|
j.add_progress()
|
||||||
except SAXException:
|
self.groups = groups
|
||||||
return
|
for dupe_file in marked:
|
||||||
self.groups = handler.groups
|
|
||||||
for dupe_file in handler.marked:
|
|
||||||
self.mark(dupe_file)
|
self.mark(dupe_file)
|
||||||
|
|
||||||
def make_ref(self, dupe):
|
def make_ref(self, dupe):
|
||||||
@@ -256,13 +266,10 @@ class Results(Markable):
|
|||||||
|
|
||||||
def save_to_xml(self, outfile):
|
def save_to_xml(self, outfile):
|
||||||
self.apply_filter(None)
|
self.apply_filter(None)
|
||||||
outfile, must_close = open_if_filename(outfile, 'wb')
|
root = etree.Element('results')
|
||||||
writer = XMLGenerator(outfile, 'utf-8')
|
# writer = XMLGenerator(outfile, 'utf-8')
|
||||||
writer.startDocument()
|
|
||||||
empty_attrs = AttributesImpl({})
|
|
||||||
writer.startElement('results', empty_attrs)
|
|
||||||
for g in self.groups:
|
for g in self.groups:
|
||||||
writer.startElement('group', empty_attrs)
|
group_elem = etree.SubElement(root, 'group')
|
||||||
dupe2index = {}
|
dupe2index = {}
|
||||||
for index, d in enumerate(g):
|
for index, d in enumerate(g):
|
||||||
dupe2index[d] = index
|
dupe2index[d] = index
|
||||||
@@ -270,27 +277,19 @@ class Results(Markable):
|
|||||||
words = engine.unpack_fields(d.words)
|
words = engine.unpack_fields(d.words)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
words = ()
|
words = ()
|
||||||
attrs = AttributesImpl({
|
file_elem = etree.SubElement(group_elem, 'file')
|
||||||
'path': unicode(d.path),
|
file_elem.set('path', unicode(d.path))
|
||||||
'is_ref': cond(d.is_ref, 'y', 'n'),
|
file_elem.set('is_ref', ('y' if d.is_ref else 'n'))
|
||||||
'words': ','.join(words),
|
file_elem.set('words', ','.join(words))
|
||||||
'marked': cond(self.is_marked(d), 'y', 'n')
|
file_elem.set('marked', ('y' if self.is_marked(d) else 'n'))
|
||||||
})
|
|
||||||
writer.startElement('file', attrs)
|
|
||||||
writer.endElement('file')
|
|
||||||
for match in g.matches:
|
for match in g.matches:
|
||||||
attrs = AttributesImpl({
|
match_elem = etree.SubElement(group_elem, 'match')
|
||||||
'first': str(dupe2index[match.first]),
|
match_elem.set('first', unicode(dupe2index[match.first]))
|
||||||
'second': str(dupe2index[match.second]),
|
match_elem.set('second', unicode(dupe2index[match.second]))
|
||||||
'percentage': str(int(match.percentage)),
|
match_elem.set('percentage', unicode(int(match.percentage)))
|
||||||
})
|
tree = etree.ElementTree(root)
|
||||||
writer.startElement('match', attrs)
|
with FileOrPath(outfile, 'wb') as fp:
|
||||||
writer.endElement('match')
|
tree.write(fp, encoding='utf-8')
|
||||||
writer.endElement('group')
|
|
||||||
writer.endElement('results')
|
|
||||||
writer.endDocument()
|
|
||||||
if must_close:
|
|
||||||
outfile.close()
|
|
||||||
|
|
||||||
def sort_dupes(self, key, asc=True, delta=False):
|
def sort_dupes(self, key, asc=True, delta=False):
|
||||||
if not self.__dupes:
|
if not self.__dupes:
|
||||||
@@ -310,60 +309,3 @@ class Results(Markable):
|
|||||||
dupes = property(__get_dupe_list)
|
dupes = property(__get_dupe_list)
|
||||||
groups = property(__get_groups, __set_groups)
|
groups = property(__get_groups, __set_groups)
|
||||||
stat_line = property(__get_stat_line)
|
stat_line = property(__get_stat_line)
|
||||||
|
|
||||||
class _ResultsHandler(handler.ContentHandler):
|
|
||||||
def __init__(self, get_file):
|
|
||||||
self.group = None
|
|
||||||
self.dupes = None
|
|
||||||
self.marked = set()
|
|
||||||
self.groups = []
|
|
||||||
self.get_file = get_file
|
|
||||||
|
|
||||||
def startElement(self, name, attrs):
|
|
||||||
if name == 'group':
|
|
||||||
self.group = engine.Group()
|
|
||||||
self.dupes = []
|
|
||||||
return
|
|
||||||
if (name == 'file') and (self.group is not None):
|
|
||||||
if not (('path' in attrs) and ('words' in attrs)):
|
|
||||||
return
|
|
||||||
path = attrs['path']
|
|
||||||
file = self.get_file(path)
|
|
||||||
if file is None:
|
|
||||||
return
|
|
||||||
file.words = attrs['words'].split(',')
|
|
||||||
file.is_ref = attrs.get('is_ref') == 'y'
|
|
||||||
self.dupes.append(file)
|
|
||||||
if attrs.get('marked') == 'y':
|
|
||||||
self.marked.add(file)
|
|
||||||
if (name == 'match') and (self.group is not None):
|
|
||||||
try:
|
|
||||||
first_file = self.dupes[int(attrs['first'])]
|
|
||||||
second_file = self.dupes[int(attrs['second'])]
|
|
||||||
percentage = int(attrs['percentage'])
|
|
||||||
self.group.add_match(engine.Match(first_file, second_file, percentage))
|
|
||||||
except (IndexError, KeyError, ValueError): # Covers missing attr, non-int values and indexes out of bounds
|
|
||||||
pass
|
|
||||||
|
|
||||||
def endElement(self, name):
|
|
||||||
def do_match(ref_file, other_files, group):
|
|
||||||
if not other_files:
|
|
||||||
return
|
|
||||||
for other_file in other_files:
|
|
||||||
group.add_match(engine.get_match(ref_file, other_file))
|
|
||||||
do_match(other_files[0], other_files[1:], group)
|
|
||||||
|
|
||||||
if name == 'group':
|
|
||||||
group = self.group
|
|
||||||
self.group = None
|
|
||||||
dupes = self.dupes
|
|
||||||
self.dupes = []
|
|
||||||
if group is None:
|
|
||||||
return
|
|
||||||
if len(dupes) < 2:
|
|
||||||
return
|
|
||||||
if not group.matches: # <match> elements not present, do it manually, without %
|
|
||||||
do_match(dupes[0], dupes[1:], group)
|
|
||||||
group.prioritize(lambda x: dupes.index(x))
|
|
||||||
self.groups.append(group)
|
|
||||||
|
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ class TCDupeGuruWithResults(TestCase):
|
|||||||
self.rtree.selected_paths = paths
|
self.rtree.selected_paths = paths
|
||||||
self.app.remove_selected()
|
self.app.remove_selected()
|
||||||
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
|
# The first 2 dupes have been removed. The 3rd one is a ref. it stays there, in first pos.
|
||||||
eq_(self.rtree.selected_paths, [[0]]) # no exception
|
eq_(self.rtree.selected_paths, [[0, 0]]) # no exception
|
||||||
|
|
||||||
def test_selectResultNodePaths(self):
|
def test_selectResultNodePaths(self):
|
||||||
app = self.app
|
app = self.app
|
||||||
@@ -366,10 +366,7 @@ class TCDupeGuruWithResults(TestCase):
|
|||||||
app = self.app
|
app = self.app
|
||||||
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
self.rtree.selected_paths = [[0, 0], [1, 0]]
|
||||||
app.remove_selected()
|
app.remove_selected()
|
||||||
eq_(len(app.results.dupes), 1)
|
eq_(len(app.results.dupes), 1) # the first path is now selected
|
||||||
app.remove_selected()
|
|
||||||
eq_(len(app.results.dupes), 1)
|
|
||||||
self.rtree.selected_path = [0, 0]
|
|
||||||
app.remove_selected()
|
app.remove_selected()
|
||||||
eq_(len(app.results.dupes), 0)
|
eq_(len(app.results.dupes), 0)
|
||||||
|
|
||||||
|
|||||||
@@ -229,10 +229,9 @@ class TCbuild_word_dict(TestCase):
|
|||||||
self.log = []
|
self.log = []
|
||||||
s = "foo bar"
|
s = "foo bar"
|
||||||
build_word_dict([NamedObject(s, True), NamedObject(s, True), NamedObject(s, True)], j)
|
build_word_dict([NamedObject(s, True), NamedObject(s, True), NamedObject(s, True)], j)
|
||||||
|
# We don't have intermediate log because iter_with_progress is called with every > 1
|
||||||
self.assertEqual(0,self.log[0])
|
self.assertEqual(0,self.log[0])
|
||||||
self.assertEqual(33,self.log[1])
|
self.assertEqual(100,self.log[1])
|
||||||
self.assertEqual(66,self.log[2])
|
|
||||||
self.assertEqual(100,self.log[3])
|
|
||||||
|
|
||||||
|
|
||||||
class TCmerge_similar_words(TestCase):
|
class TCmerge_similar_words(TestCase):
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import cStringIO
|
import cStringIO
|
||||||
import xml.dom.minidom
|
from lxml import etree
|
||||||
|
|
||||||
from nose.tools import eq_
|
from nose.tools import eq_
|
||||||
|
|
||||||
@@ -62,16 +62,14 @@ def test_save_to_xml():
|
|||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
eq_('ignore_list',root.nodeName)
|
eq_(root.tag, 'ignore_list')
|
||||||
children = [c for c in root.childNodes if c.localName]
|
eq_(len(root), 2)
|
||||||
eq_(2,len(children))
|
eq_(len([c for c in root if c.tag == 'file']), 2)
|
||||||
eq_(2,len([c for c in children if c.nodeName == 'file']))
|
f1, f2 = root[:]
|
||||||
f1,f2 = children
|
subchildren = [c for c in f1 if c.tag == 'file'] + [c for c in f2 if c.tag == 'file']
|
||||||
subchildren = [c for c in f1.childNodes if c.localName == 'file'] +\
|
eq_(len(subchildren), 3)
|
||||||
[c for c in f2.childNodes if c.localName == 'file']
|
|
||||||
eq_(3,len(subchildren))
|
|
||||||
|
|
||||||
def test_SaveThenLoad():
|
def test_SaveThenLoad():
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
@@ -82,6 +80,7 @@ def test_SaveThenLoad():
|
|||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
|
f.seek(0)
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
il.load_from_xml(f)
|
il.load_from_xml(f)
|
||||||
eq_(4,len(il))
|
eq_(4,len(il))
|
||||||
@@ -129,9 +128,9 @@ def test_filter():
|
|||||||
assert not il.AreIgnored('foo','bar')
|
assert not il.AreIgnored('foo','bar')
|
||||||
assert il.AreIgnored('bar','baz')
|
assert il.AreIgnored('bar','baz')
|
||||||
|
|
||||||
def test_save_with_non_ascii_non_unicode_items():
|
def test_save_with_non_ascii_items():
|
||||||
il = IgnoreList()
|
il = IgnoreList()
|
||||||
il.Ignore('\xac','\xbf')
|
il.Ignore(u'\xac', u'\xbf')
|
||||||
f = cStringIO.StringIO()
|
f = cStringIO.StringIO()
|
||||||
try:
|
try:
|
||||||
il.save_to_xml(f)
|
il.save_to_xml(f)
|
||||||
|
|||||||
@@ -7,10 +7,9 @@
|
|||||||
# which should be included with this package. The terms are also available at
|
# which should be included with this package. The terms are also available at
|
||||||
# http://www.hardcoded.net/licenses/hs_license
|
# http://www.hardcoded.net/licenses/hs_license
|
||||||
|
|
||||||
import unittest
|
|
||||||
import StringIO
|
import StringIO
|
||||||
import xml.dom.minidom
|
|
||||||
import os.path as op
|
import os.path as op
|
||||||
|
from lxml import etree
|
||||||
|
|
||||||
from hsutil.path import Path
|
from hsutil.path import Path
|
||||||
from hsutil.testcase import TestCase
|
from hsutil.testcase import TestCase
|
||||||
@@ -18,7 +17,7 @@ from hsutil.misc import first
|
|||||||
|
|
||||||
from . import engine_test, data
|
from . import engine_test, data
|
||||||
from .. import engine
|
from .. import engine
|
||||||
from ..results import *
|
from ..results import Results
|
||||||
|
|
||||||
class NamedObject(engine_test.NamedObject):
|
class NamedObject(engine_test.NamedObject):
|
||||||
path = property(lambda x:Path('basepath') + x.name)
|
path = property(lambda x:Path('basepath') + x.name)
|
||||||
@@ -65,9 +64,9 @@ class TCResultsEmpty(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
self.assertEqual('results',root.nodeName)
|
self.assertEqual('results', root.tag)
|
||||||
|
|
||||||
|
|
||||||
class TCResultsWithSomeGroups(TestCase):
|
class TCResultsWithSomeGroups(TestCase):
|
||||||
@@ -321,16 +320,16 @@ class TCResultsMarkings(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
g1,g2 = root.getElementsByTagName('group')
|
g1, g2 = root.iterchildren('group')
|
||||||
d1,d2,d3 = g1.getElementsByTagName('file')
|
d1, d2, d3 = g1.iterchildren('file')
|
||||||
self.assertEqual('n',d1.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d1.get('marked'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d2.get('marked'))
|
||||||
self.assertEqual('y',d3.getAttributeNode('marked').nodeValue)
|
self.assertEqual('y', d3.get('marked'))
|
||||||
d1,d2 = g2.getElementsByTagName('file')
|
d1, d2 = g2.iterchildren('file')
|
||||||
self.assertEqual('n',d1.getAttributeNode('marked').nodeValue)
|
self.assertEqual('n', d1.get('marked'))
|
||||||
self.assertEqual('y',d2.getAttributeNode('marked').nodeValue)
|
self.assertEqual('y', d2.get('marked'))
|
||||||
|
|
||||||
def test_LoadXML(self):
|
def test_LoadXML(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
@@ -366,38 +365,35 @@ class TCResultsXML(TestCase):
|
|||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
self.results.save_to_xml(f)
|
self.results.save_to_xml(f)
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
doc = xml.dom.minidom.parse(f)
|
doc = etree.parse(f)
|
||||||
root = doc.documentElement
|
root = doc.getroot()
|
||||||
self.assertEqual('results',root.nodeName)
|
self.assertEqual('results', root.tag)
|
||||||
children = [c for c in root.childNodes if c.localName]
|
self.assertEqual(2, len(root))
|
||||||
self.assertEqual(2,len(children))
|
self.assertEqual(2, len([c for c in root if c.tag == 'group']))
|
||||||
self.assertEqual(2,len([c for c in children if c.nodeName == 'group']))
|
g1, g2 = root
|
||||||
g1,g2 = children
|
self.assertEqual(6,len(g1))
|
||||||
children = [c for c in g1.childNodes if c.localName]
|
self.assertEqual(3,len([c for c in g1 if c.tag == 'file']))
|
||||||
self.assertEqual(6,len(children))
|
self.assertEqual(3,len([c for c in g1 if c.tag == 'match']))
|
||||||
self.assertEqual(3,len([c for c in children if c.nodeName == 'file']))
|
d1, d2, d3 = [c for c in g1 if c.tag == 'file']
|
||||||
self.assertEqual(3,len([c for c in children if c.nodeName == 'match']))
|
self.assertEqual(op.join('basepath','foo bar'),d1.get('path'))
|
||||||
d1,d2,d3 = [c for c in children if c.nodeName == 'file']
|
self.assertEqual(op.join('basepath','bar bleh'),d2.get('path'))
|
||||||
self.assertEqual(op.join('basepath','foo bar'),d1.getAttributeNode('path').nodeValue)
|
self.assertEqual(op.join('basepath','foo bleh'),d3.get('path'))
|
||||||
self.assertEqual(op.join('basepath','bar bleh'),d2.getAttributeNode('path').nodeValue)
|
self.assertEqual('y',d1.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','foo bleh'),d3.getAttributeNode('path').nodeValue)
|
self.assertEqual('n',d2.get('is_ref'))
|
||||||
self.assertEqual('y',d1.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('n',d3.get('is_ref'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('foo,bar',d1.get('words'))
|
||||||
self.assertEqual('n',d3.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('bar,bleh',d2.get('words'))
|
||||||
self.assertEqual('foo,bar',d1.getAttributeNode('words').nodeValue)
|
self.assertEqual('foo,bleh',d3.get('words'))
|
||||||
self.assertEqual('bar,bleh',d2.getAttributeNode('words').nodeValue)
|
self.assertEqual(3,len(g2))
|
||||||
self.assertEqual('foo,bleh',d3.getAttributeNode('words').nodeValue)
|
self.assertEqual(2,len([c for c in g2 if c.tag == 'file']))
|
||||||
children = [c for c in g2.childNodes if c.localName]
|
self.assertEqual(1,len([c for c in g2 if c.tag == 'match']))
|
||||||
self.assertEqual(3,len(children))
|
d1, d2 = [c for c in g2 if c.tag == 'file']
|
||||||
self.assertEqual(2,len([c for c in children if c.nodeName == 'file']))
|
self.assertEqual(op.join('basepath','ibabtu'),d1.get('path'))
|
||||||
self.assertEqual(1,len([c for c in children if c.nodeName == 'match']))
|
self.assertEqual(op.join('basepath','ibabtu'),d2.get('path'))
|
||||||
d1,d2 = [c for c in children if c.nodeName == 'file']
|
self.assertEqual('n',d1.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','ibabtu'),d1.getAttributeNode('path').nodeValue)
|
self.assertEqual('n',d2.get('is_ref'))
|
||||||
self.assertEqual(op.join('basepath','ibabtu'),d2.getAttributeNode('path').nodeValue)
|
self.assertEqual('ibabtu',d1.get('words'))
|
||||||
self.assertEqual('n',d1.getAttributeNode('is_ref').nodeValue)
|
self.assertEqual('ibabtu',d2.get('words'))
|
||||||
self.assertEqual('n',d2.getAttributeNode('is_ref').nodeValue)
|
|
||||||
self.assertEqual('ibabtu',d1.getAttributeNode('words').nodeValue)
|
|
||||||
self.assertEqual('ibabtu',d2.getAttributeNode('words').nodeValue)
|
|
||||||
|
|
||||||
def test_LoadXML(self):
|
def test_LoadXML(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
@@ -460,41 +456,41 @@ class TCResultsXML(TestCase):
|
|||||||
def get_file(path):
|
def get_file(path):
|
||||||
return [f for f in self.objects if str(f.path) == path][0]
|
return [f for f in self.objects if str(f.path) == path][0]
|
||||||
|
|
||||||
doc = xml.dom.minidom.Document()
|
root = etree.Element('foobar') #The root element shouldn't matter, really.
|
||||||
root = doc.appendChild(doc.createElement('foobar')) #The root element shouldn't matter, really.
|
group_node = etree.SubElement(root, 'group')
|
||||||
group_node = root.appendChild(doc.createElement('group'))
|
dupe_node = etree.SubElement(group_node, 'file') #Perfectly correct file
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #Perfectly correct file
|
dupe_node.set('path', op.join('basepath','foo bar'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','foo bar'))
|
dupe_node.set('is_ref', 'y')
|
||||||
dupe_node.setAttribute('is_ref','y')
|
dupe_node.set('words', 'foo,bar')
|
||||||
dupe_node.setAttribute('words','foo,bar')
|
dupe_node = etree.SubElement(group_node, 'file') #is_ref missing, default to 'n'
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #is_ref missing, default to 'n'
|
dupe_node.set('path',op.join('basepath','foo bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','foo bleh'))
|
dupe_node.set('words','foo,bleh')
|
||||||
dupe_node.setAttribute('words','foo,bleh')
|
dupe_node = etree.SubElement(group_node, 'file') #words are missing, valid.
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #words are missing, invalid.
|
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','bar bleh'))
|
dupe_node = etree.SubElement(group_node, 'file') #path is missing, invalid.
|
||||||
dupe_node = group_node.appendChild(doc.createElement('file')) #path is missing, invalid.
|
dupe_node.set('words','foo,bleh')
|
||||||
dupe_node.setAttribute('words','foo,bleh')
|
dupe_node = etree.SubElement(group_node, 'foobar') #Invalid element name
|
||||||
dupe_node = group_node.appendChild(doc.createElement('foobar')) #Invalid element name
|
dupe_node.set('path',op.join('basepath','bar bleh'))
|
||||||
dupe_node.setAttribute('path',op.join('basepath','bar bleh'))
|
dupe_node.set('is_ref','y')
|
||||||
dupe_node.setAttribute('is_ref','y')
|
dupe_node.set('words','bar,bleh')
|
||||||
dupe_node.setAttribute('words','bar,bleh')
|
match_node = etree.SubElement(group_node, 'match') # match pointing to a bad index
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match pointing to a bad index
|
match_node.set('first', '42')
|
||||||
match_node.setAttribute('first', '42')
|
match_node.set('second', '45')
|
||||||
match_node.setAttribute('second', '45')
|
match_node = etree.SubElement(group_node, 'match') # match with missing attrs
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match with missing attrs
|
match_node = etree.SubElement(group_node, 'match') # match with non-int values
|
||||||
match_node = group_node.appendChild(doc.createElement('match')) # match with non-int values
|
match_node.set('first', 'foo')
|
||||||
match_node.setAttribute('first', 'foo')
|
match_node.set('second', 'bar')
|
||||||
match_node.setAttribute('second', 'bar')
|
match_node.set('percentage', 'baz')
|
||||||
match_node.setAttribute('percentage', 'baz')
|
group_node = etree.SubElement(root, 'foobar') #invalid group
|
||||||
group_node = root.appendChild(doc.createElement('foobar')) #invalid group
|
group_node = etree.SubElement(root, 'group') #empty group
|
||||||
group_node = root.appendChild(doc.createElement('group')) #empty group
|
|
||||||
f = StringIO.StringIO()
|
f = StringIO.StringIO()
|
||||||
doc.writexml(f,'\t','\t','\n',encoding='utf-8')
|
tree = etree.ElementTree(root)
|
||||||
|
tree.write(f, encoding='utf-8')
|
||||||
f.seek(0)
|
f.seek(0)
|
||||||
r = Results(data)
|
r = Results(data)
|
||||||
r.load_from_xml(f, get_file)
|
r.load_from_xml(f, get_file)
|
||||||
self.assertEqual(1,len(r.groups))
|
self.assertEqual(1,len(r.groups))
|
||||||
self.assertEqual(2,len(r.groups[0]))
|
self.assertEqual(3,len(r.groups[0]))
|
||||||
|
|
||||||
def test_xml_non_ascii(self):
|
def test_xml_non_ascii(self):
|
||||||
def get_file(path):
|
def get_file(path):
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import logging
|
|||||||
import plistlib
|
import plistlib
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
from appscript import app, k, CommandError
|
from appscript import app, k, CommandError
|
||||||
|
|
||||||
from hsutil import io
|
from hsutil import io
|
||||||
@@ -68,15 +69,10 @@ def get_iphoto_database_path():
|
|||||||
def get_iphoto_pictures(plistpath):
|
def get_iphoto_pictures(plistpath):
|
||||||
if not io.exists(plistpath):
|
if not io.exists(plistpath):
|
||||||
return []
|
return []
|
||||||
s = io.open(plistpath).read()
|
# We make the xml go through lxml so that it can fix broken xml which iPhoto sometimes produces.
|
||||||
# There was a case where a guy had 0x10 chars in his plist, causing expat errors on loading
|
parser = etree.XMLParser(recover=True)
|
||||||
s = s.replace('\x10', '')
|
root = etree.parse(io.open(plistpath), parser=parser).getroot()
|
||||||
# It seems that iPhoto sometimes doesn't properly escape & chars. The regexp below is to find
|
s = etree.tostring(root)
|
||||||
# any & char that is not a &-based entity (&, ", etc.). based on TextMate's XML
|
|
||||||
# bundle's regexp
|
|
||||||
s, count = re.subn(r'&(?![a-zA-Z0-9_-]+|#[0-9]+|#x[0-9a-fA-F]+;)', '', s)
|
|
||||||
if count:
|
|
||||||
logging.warning("%d invalid XML entities replacement made", count)
|
|
||||||
plist = plistlib.readPlistFromString(s)
|
plist = plistlib.readPlistFromString(s)
|
||||||
result = []
|
result = []
|
||||||
for photo_data in plist['Master Image List'].values():
|
for photo_data in plist['Master Image List'].values():
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
- date: 2010-03-01
|
||||||
|
version: 1.8.5
|
||||||
|
description: |
|
||||||
|
* Fixed a bug preventing some iPhoto Libraries to be read. (Mac OS X)
|
||||||
|
* Improved results loading and saving speed.
|
||||||
- date: 2010-02-18
|
- date: 2010-02-18
|
||||||
version: 1.8.4
|
version: 1.8.4
|
||||||
description: |
|
description: |
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class File(fs.File):
|
|||||||
class DupeGuru(DupeGuruBase):
|
class DupeGuru(DupeGuruBase):
|
||||||
LOGO_NAME = 'logo_pe'
|
LOGO_NAME = 'logo_pe'
|
||||||
NAME = 'dupeGuru Picture Edition'
|
NAME = 'dupeGuru Picture Edition'
|
||||||
VERSION = '1.8.4'
|
VERSION = '1.8.5'
|
||||||
DELTA_COLUMNS = frozenset([2, 5, 6])
|
DELTA_COLUMNS = frozenset([2, 5, 6])
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user