Frank Shearar uploaded a new version of ReleaseBuilder to project The Trunk:
http://source.squeak.org/trunk/ReleaseBuilder-fbs.100.mcz
==================== Summary ====================
Name: ReleaseBuilder-fbs.100
Author: fbs
Time: 4 July 2013, 7:14:55.532 pm
UUID: 4d26e79c-81fc-df47-af42-10cbe2238e4f
Ancestors: ReleaseBuilder-fbs.99
Log more during the release process. Use stdout because running this from a command line is the most common use case.
=============== Diff against ReleaseBuilder-fbs.99 ===============
Item was changed:
----- Method: ReleaseBuilder class>>cleanPackages (in category 'scripts') -----
cleanPackages
"Force-load the packages to ensure the image has what Trunk says it should."
| trunk |
trunk := MCRepositoryGroup default repositories detect:
[:repo | repo description = 'http://source.squeak.org/trunk'].
+ MCWorkingCopy allManagers do: [:wc |
+ FileStream stdout nextPutAll: ('Cleaning {1}\' withCRs format: {wc packageName}).
+ wc ancestors size = 1 ifFalse: [
+ self error: 'Package must have single parent: ', wc packageName].
- MCWorkingCopy allManagers
- do: [:wc |
- wc ancestors size = 1 ifFalse: [
- self error: 'Package must have single parent: ', wc packageName].
wc modified: true. "make sure actual diff is performed"
[(trunk versionWithInfo: wc ancestors first) load]
+ on: Warning do: [:w | w resume]].!
- on: Warning do: [:w | w resume]]
- displayingProgress: 'Cleaning packages'.!
Item was changed:
----- Method: ReleaseBuilder class>>loadWellKnownPackages (in category 'private') -----
loadWellKnownPackages
"Load into the release image those packages that have been stripped from Trunk, but still deemed necessary for a release artifact."
#('311Deprecated'
'39Deprecated'
'45Deprecated'
'Nebraska'
'SmallLand-ColorTheme'
'ST80'
'ST80Tools'
'Universes'
'XML-Parser') do: [:pkgName |
+ FileStream stdout nextPutAll: ('Loading {1}\' withCRs format: {pkgName}).
Installer squeak
project: 'trunk';
install: pkgName].!
On Fri, 28 Jun 2013, commits(a)source.squeak.org wrote:
> A new version of Files was added to project The Inbox:
> http://source.squeak.org/inbox/Files-cmm.125.mcz
>
> ==================== Summary ====================
>
> Name: Files-cmm.125
> Author: cmm
> Time: 27 June 2013, 7:24:33.37 pm
> UUID: 0b00b2c4-3430-442b-a924-72040ff43d73
> Ancestors: Files-fbs.124
>
> FileDirectory>>statsForDirectoryTree: is a prime example of FileDirectory living up to its poor reputation. It does one useless thing, and does it inefficiently. It has no senders, deservedly.
> Tree-walking operations like gathering stats can be written in apps more generally using directoryTreeDo:.
I wouldn't say it's inefficient. It uses BFS (instead of DFS, which is
used by #directoryTreeDo:entries:), which is somewhat better than DFS,
because of the way FilePlugin works: you have to iterate over the contents
of the whole directory if you want to it to be efficient.
If you use DFS, then the contents of all parent directories up to the
root will have to be stored in memory during the iteration, while if you
use BFS, then only the sibling directories (without their contents) or the
siblings's parents will be in memory.
I made two "new" implementations of #statsForDirectoryTree:. This one
optimizes memory usage for BFS:
statsForDirectoryTree2: rootedPathName
| dirs files bytes todo |
dirs := files := bytes := 0.
todo := OrderedCollection with: rootedPathName.
[ todo isEmpty ] whileFalse: [
| p |
p := todo removeFirst.
self directoryContentsFor: p do: [ :entry |
entry isDirectory
ifTrue: [
todo addLast: p , self pathNameDelimiter asString , entry name.
dirs := dirs + 1]
ifFalse: [
files := files + 1.
bytes := bytes + entry fileSize ] ] ].
^{ dirs. files. bytes }
This one uses #directoryTreeDo::
statsForDirectoryTree3: rootedPathName
| dirs files bytes |
dirs := files := bytes := 0.
(FileDirectory on: rootedPathName) directoryTreeDo: [ :path |
| entry |
entry := path last.
entry isDirectory
ifTrue: [ dirs := dirs + 1 ]
ifFalse: [
files := files + 1.
bytes := bytes + entry fileSize ] ].
^{ dirs. files. bytes }
Let's see the numbers:
"Make sure the disk won't be accessed"
FileDirectory default statsForDirectoryTree: '/usr/'.
FileDirectory default statsForDirectoryTree: '/usr/'.
"Run the benchmark"
#(statsForDirectoryTree: statsForDirectoryTree2: statsForDirectoryTree3:) collect: [ :each |
each -> ((1 to: 5) collect: [ :run |
Smalltalk garbageCollect.
[ FileDirectory default perform: each with: '/usr/' ] timeToRun ]) ].
{
#statsForDirectoryTree:->#(6340 6300 6430 6316 6228) .
#statsForDirectoryTree2:->#(5918 6072 6122 6296 6306) .
#statsForDirectoryTree3:->#(8576 8374 8470 8506 8228) }
It's a bit noisy (i was too lazy to exit other programs), but the one
using #directoryTreeDo: seems to be clearly slower than the existing
algorithm using BFS.
Levente
>
> =============== Diff against Files-fbs.124 ===============
>
> Item was changed:
> + ----- Method: FileDirectory>>directoryTreeDo:entries: (in category 'private') -----
> - ----- Method: FileDirectory>>directoryTreeDo:entries: (in category 'enumeration') -----
> directoryTreeDo: oneArgBlock entries: entriesCollection
> "Value oneArgBlock with the path (an OrderedCollection of FileDirectory's) to each DirectoryEntry and the DirectoryEntry itself."
> self entries do:
> [ : each |
> entriesCollection add: each.
> oneArgBlock value: entriesCollection.
> each isDirectory ifTrue:
> [ | subdir |
> subdir := each asFileDirectory.
> subdir
> directoryTreeDo: oneArgBlock
> entries: entriesCollection ].
> entriesCollection removeLast ]!
>
> Item was removed:
> - ----- Method: FileDirectory>>statsForDirectoryTree: (in category 'enumeration') -----
> - statsForDirectoryTree: rootedPathName
> - "Return the size statistics for the entire directory tree starting at the given root. The result is a three element array of the form: (<number of folders><number of files><total bytes in all files>). This method also serves as an example of how recursively enumerate a directory tree."
> - "FileDirectory default statsForDirectoryTree: '\smalltalk'"
> -
> - | dirs files bytes todo entries p |
> - dirs := files := bytes := 0.
> - todo := OrderedCollection with: rootedPathName.
> - [todo isEmpty] whileFalse: [
> - p := todo removeFirst.
> - entries := self directoryContentsFor: p.
> - entries do: [:entry |
> - entry isDirectory
> - ifTrue: [
> - todo addLast: p , self pathNameDelimiter asString , entry name.
> - dirs := dirs + 1]
> - ifFalse: [
> - files := files + 1.
> - bytes := bytes + entry fileSize]]].
> - ^ Array with: dirs with: files with: bytes
> - !
>
>
>
On Wed, 3 Jul 2013, commits(a)source.squeak.org wrote:
> A new version of Files was added to project The Inbox:
> http://source.squeak.org/inbox/Files-ul.125.mcz
>
> ==================== Summary ====================
>
> Name: Files-ul.125
> Author: ul
> Time: 3 July 2013, 7:35:48.693 am
> UUID: 5a53740b-df37-4fb1-90af-d803dbda9593
> Ancestors: Files-fbs.124
>
> FileDirectory >> #directoryTreeDo: uses BFS instead of DFS.
> FileDirectory >> #statsForDirectoryTree: uses #directoryTreeDo: instead of reimplementing a BFS algorithm.
>
> =============== Diff against Files-fbs.124 ===============
>
> Item was changed:
> ----- Method: FileDirectory>>directoryTreeDo: (in category 'enumeration') -----
> directoryTreeDo: oneArgBlock
> "For each file and directory in my tree, value oneArgBlock with an OrderedCollection of the path of DirectoryEntry's leading to the current node. The first element in the collection will be the DirectoryEntryDirectory for myself, the last is the currentNode (a DirectoryEntry)."
> + "Implementation details:
> + This is a simple BFS algorithm with additional stuff to ensure that the path to the root directory is available. The elements in the queue (aka the graph nodes) are tuples. Each tuple has 3 elements: a DirectoryEntry, the parent tuple, and the length of the path to the root. Each directory in the tree will have a corresponding tuple. Since each tuple contains a pointer to its parent directory's tuple, therefore large parts of the directory tree (not including files) will be stored in memory. Updating currentPath doesn't take more than visiting all nodes in that tree, so its total runtime cost is O(d), where d is the number of directories in the directory tree, which means that the amortized cost of keeping the path up-to-date is O(1).
This is actually not true, for sparse trees the total cost of updating the
path can be O(d*d).
Levente
> + The reason why we use BFS instead of DFS (which naturally has the path to the current entry from the root) is because the primitives in FilePlugin work better this way."
> +
> + | queue currentPath |
> + currentPath := OrderedCollection with: self directoryEntry.
> + oneArgBlock value: currentPath.
> + queue := OrderedCollection with: { currentPath first. nil. 1 }.
> + [ queue isEmpty ] whileFalse: [
> + | parentTuple fixupTuple newPathLength |
> + parentTuple := queue removeFirst.
> + "Update currentPath to contain the entries to parentTuple from the root."
> + fixupTuple := parentTuple.
> + currentPath size < fixupTuple third ifTrue: [ "Next row in the tree, extend the path."
> + currentPath add: fixupTuple first.
> + fixupTuple := fixupTuple second ].
> + [ (currentPath at: fixupTuple third) == fixupTuple first ] whileFalse: [
> + currentPath at: fixupTuple third put: fixupTuple first.
> + fixupTuple := fixupTuple second ].
> + "Visit the sub-entries"
> + newPathLength := parentTuple third + 1.
> + currentPath add: nil. "Extend the path with a new slot"
> + parentTuple first asFileDirectory entriesDo: [ :entry |
> + currentPath atLast: 1 put: entry.
> + oneArgBlock value: currentPath.
> + entry isDirectory ifTrue: [
> + queue addLast: { entry. parentTuple. newPathLength } ] ].
> + currentPath removeLast ]!
> - |myEntry|
> - myEntry := OrderedCollection with: self directoryEntry.
> - oneArgBlock value: myEntry.
> - self
> - directoryTreeDo: oneArgBlock
> - entries: myEntry!
>
> Item was removed:
> - ----- Method: FileDirectory>>directoryTreeDo:entries: (in category 'enumeration') -----
> - directoryTreeDo: oneArgBlock entries: entriesCollection
> - "Value oneArgBlock with the path (an OrderedCollection of FileDirectory's) to each DirectoryEntry and the DirectoryEntry itself."
> - self entries do:
> - [ : each |
> - entriesCollection add: each.
> - oneArgBlock value: entriesCollection.
> - each isDirectory ifTrue:
> - [ | subdir |
> - subdir := each asFileDirectory.
> - subdir
> - directoryTreeDo: oneArgBlock
> - entries: entriesCollection ].
> - entriesCollection removeLast ]!
>
> Item was added:
> + ----- Method: FileDirectory>>entriesDo: (in category 'enumeration') -----
> + entriesDo: oneArgumentBlock
> + "Evaluate oneArgumentBlock with DirectoryEntry objects for the files and directories in this directory."
> +
> + ^self directoryContentsFor: pathName do: oneArgumentBlock
> + !
>
> Item was changed:
> ----- Method: FileDirectory>>statsForDirectoryTree: (in category 'enumeration') -----
> statsForDirectoryTree: rootedPathName
> "Return the size statistics for the entire directory tree starting at the given root. The result is a three element array of the form: (<number of folders><number of files><total bytes in all files>). This method also serves as an example of how recursively enumerate a directory tree."
> "FileDirectory default statsForDirectoryTree: '\smalltalk'"
>
> + | dirs files bytes |
> - | dirs files bytes todo entries p |
> dirs := files := bytes := 0.
> + (FileDirectory on: rootedPathName) directoryTreeDo: [ :path |
> + | entry |
> + entry := path last.
> + entry isDirectory
> + ifTrue: [ dirs := dirs + 1 ]
> + ifFalse: [
> + files := files + 1.
> + bytes := bytes + entry fileSize ] ].
> + ^{ dirs. files. bytes }
> - todo := OrderedCollection with: rootedPathName.
> - [todo isEmpty] whileFalse: [
> - p := todo removeFirst.
> - entries := self directoryContentsFor: p.
> - entries do: [:entry |
> - entry isDirectory
> - ifTrue: [
> - todo addLast: p , self pathNameDelimiter asString , entry name.
> - dirs := dirs + 1]
> - ifFalse: [
> - files := files + 1.
> - bytes := bytes + entry fileSize]]].
> - ^ Array with: dirs with: files with: bytes
> !
>
>
>
On 3 July 2013 22:29, <commits(a)source.squeak.org> wrote:
> Frank Shearar uploaded a new version of PackageInfo-UI to project The Trunk:
> http://source.squeak.org/trunk/PackageInfo-UI-fbs.1.mcz
>
> ==================== Summary ====================
>
> Name: PackageInfo-UI-fbs.1
> Author: fbs
> Time: 3 July 2013, 10:29:09.239 pm
> UUID: 47ca3033-6938-2d4f-9ff6-02b2345a1fc5
> Ancestors:
>
> Split PackageInfo's UI into a separate package.
>
> ==================== Snapshot ====================
PackageList needs to be rewritten to use ToolBuilder. It ought to be a
small project for someone looking to dip their toe into writing
graphical framework agnostic user interfaces...
frank
Frank Shearar uploaded a new version of PackageInfo-UI to project The Trunk:
http://source.squeak.org/trunk/PackageInfo-UI-fbs.2.mcz
==================== Summary ====================
Name: PackageInfo-UI-fbs.2
Author: fbs
Time: 3 July 2013, 11:07:02.719 pm
UUID: af5ccd5d-7c6d-494c-986b-01eac1fc0b8c
Ancestors: PackageInfo-UI-fbs.1
PackageList >> #perform:orSendTo: is equivalent to Object >> #perform:orSendTo:
=============== Diff against PackageInfo-UI-fbs.1 ===============
Item was removed:
- ----- Method: PackageList>>perform:orSendTo: (in category 'morphic') -----
- perform: selector orSendTo: otherTarget
- "Selector was just chosen from a menu by a user. If can respond, then
- perform it on myself. If not, send it to otherTarget, presumably the
- editPane from which the menu was invoked."
-
- (self respondsTo: selector)
- ifTrue: [^ self perform: selector]
- ifFalse: [^ otherTarget perform: selector]!