FileURI.st
author tm
Thu, 24 Jul 2003 11:29:43 +0200
changeset 1284 57550436b55b
parent 1271 ca2e206e7c7f
child 1309 c752d54f4e09
permissions -rw-r--r--
file exists error handling

"{ Package: 'stx:libbasic2' }"

HierarchicalURI subclass:#FileURI
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'Resources'
!


!FileURI class methodsFor:'instance creation'!

fromFilename:aFilename
    "create an URI based on an a filename"

    ^ self new fromFilename:aFilename
! !

!FileURI class methodsFor:'accessing'!

schemes
    "answer the list of supported schemes"

    ^ #(file)
! !

!FileURI methodsFor:'converting'!

asFilename
    "answer the receiver represented as filename"

    ^ authority notNil ifTrue:[
        Filename remoteHost:authority rootComponents:pathSegments.
    ] ifFalse:[
        "kludge"
        (pathSegments first startsWith:$~) ifTrue:[
            pathSegments first asFilename construct:(Filename rootComponents:(pathSegments copyFrom:2)).
        ] ifFalse:[
            Filename rootComponents:pathSegments.
        ].
    ].

    "
        (URI fromString:'file:~/bla') asFilename
        (URI fromString:'file:~root/bla') asFilename 
    "
! !

!FileURI methodsFor:'initialize'!

fromFilename:aFilename
    "create an URI based on an a filename"

    |components|

    components := aFilename components.
    aFilename isAbsolute ifTrue:[
        (components size > 3 and:[(components at:2) size == 0]) ifTrue:[
            "this is a MS-Windows network path: \\host\path"
            authority := components at:3.
            pathSegments := components copyFrom:4.
        ] ifFalse:[
            "this is an absolute path"
            isAbsolute := true.
            pathSegments := components copyFrom:2.
        ].
    ] ifFalse:[
        "this is a relative path"
        isAbsolute := false.
        pathSegments := components.
    ]

    "
      self fromFilename:'/a/b/c'  asFilename   
      self fromFilename:'//a/b/c' asFilename  
      self fromFilename:'a/b/c'   asFilename    
    "
! !

!FileURI methodsFor:'queries'!

exists

    ^ self asFilename exists
! !

!FileURI methodsFor:'stream access'!

readStream

    ^ self asFilename readStream

    "
     'file:/etc/group' asURI readStream contents
     'file:/~/.profile' asURI readStream contents
     (URI fromString:'file:~/.profile') asFilename
     (URI fromString:'file:~/.profile') readStream upToEnd
    "
!

readStreamDo:aBlock
    "evaluate a block with the read stream as first argument
     and a dictionary containing attributes as second argument.
     The stream is closed after aBlock has been evaluated."

    |attributes file stream|

    attributes := self class attributes.
    file := self asFilename.
    attributes at:#fileSize put:(file fileSize).
    attributes at:#baseName put:file baseName.  
    attributes at:#uriInfo  put:self printString.  

    ^ [ 
        stream := file readStream.
        aBlock value:stream value:attributes
     ] ensure:[
        stream notNil ifTrue:[stream close]
     ].

    "
     'file:/etc/group' asURI readStreamDo:[:stream :attributes|
        stream contents         
                addFirst:attributes printString; 
                yourself
     ].
    "
!

readStreamsDo:aBlock
    "evaluate the block with a Collection of streams as first argument
     and a dictionary containing attributes as second argument,
     - a collection with a stream on a single file,
     - or a collection with streams on a directorie's files, but not recursive"

    self readStreamsDo:aBlock renameBlock:nil.
!

readStreamsDo:aBlock renameBlock:renameBlock
    "evaluate the block with a Collection of streams as first argument
     and a dictionary containing attributes as second argument,
     - a collection with a stream on a single file,
     - or a collection with streams on a directories files, but not recursive"

    |attributes fn files list baseName|

    fn := self asFilename.
    files := OrderedCollection new.
    list := OrderedCollection new.
    attributes := self class attributes.

    fn isDirectory ifTrue:[
        attributes at:#requestDirectory put:true.
        fn directoryContentsAsFilenamesDo:[:eachFilename|
            eachFilename isDirectory ifFalse:[
                files add:eachFilename
            ].
        ].
    ] ifFalse:[
        baseName := fn baseName.
        (baseName includesAny:'*?[]') ifTrue:[ |directoryName|
            attributes at:#requestDirectory put:true.
            directoryName := fn directory.
            directoryName directoryContentsDo:[:eachFilenameString|
                (baseName match:eachFilenameString) ifTrue:[ |filename|
                    filename := directoryName construct:eachFilenameString.
                    filename isDirectory ifFalse:[
                        files add:(directoryName construct:eachFilenameString).
                    ].
                ].
            ].
        ] ifFalse:[
            attributes at:#requestDirectory put:false.
            files add:fn.
        ].
    ].

    files do:[:eachFilename| |baseName stream|
        [
            baseName := eachFilename baseName.
            attributes at:#fileSize put:eachFilename fileSize.
            attributes at:#baseName put:baseName.  
            (self pathSegments includes:baseName) ifTrue:[
                attributes at:#uriInfo put:self.  
            ] ifFalse:[ |uri col|
                uri := self copy.
                col := self pathSegments copy.
                col removeLast.
                col add:baseName.
                uri pathSegments:col.
                attributes at:#uriInfo put:uri.  
            ].
            stream := eachFilename readStream.
            aBlock value:stream value:attributes.
        ] ensure:[
            stream notNil ifTrue:[stream close]
        ].

        renameBlock notNil ifTrue:[ |renameFilenameString|
            renameFilenameString := renameBlock value:eachFilename pathName.
            renameFilenameString asFilename exists ifTrue:[
                renameFilenameString := renameFilenameString, '.', 
                        (AbsoluteTime now printStringFormat:'%(year)%(mon)%(day)%h%m%s').
            ].
            eachFilename moveTo:renameFilenameString.
        ].
    ].

    "
        (URI fromString:'file:~/test/out') 
            readStreamsDo:[:stream :attributes | 
                Transcript showCR:(attributes at:#baseName).
                Transcript showCR:(attributes at:#fileSize).
                Transcript showCR:(attributes at:#requestDirectory).
                Transcript showCR:(attributes at:#uriInfo).
            ].
        (URI fromString:'file:~/test/out/*1') 
            readStreamsDo:[:stream :attributes | 
                Transcript showCR:(attributes at:#baseName).
                Transcript showCR:(attributes at:#fileSize).
                Transcript showCR:(attributes at:#requestDirectory).
                Transcript showCR:(attributes at:#uriInfo).
            ].
    "
!

writeStreamDo:aBlock
    "evaluate a block with the write stream as first argument
     and a dictionary containing attributes as second argument.
     The stream is closed after aBlock has been evaluated.
     Attributes may be the mime type (key #MIME)"

    |stream|

    ^ [
        stream := self asFilename writeStream.
        aBlock value:stream value:self class attributes
     ] ensure:[
        stream notNil ifTrue:[stream close]
     ].

    "
        (URI fromString:'file:/home/tm/tmp') 
            readStreamsDo:[:stream :attributes| 
                Transcript showCR:(attributes at:#MIME).
                Transcript showCR:(stream isWritable).
            ].
    "
!

writeStreamDo:aBlock create:doCreate

    ^ self writeStreamDo:aBlock create:doCreate atomic:false.
!

writeStreamDo:aBlock create:doCreate atomic:doAtomic
    "evaluate a block with the write stream as first argument
     and a dictionary containing attributes as second argument.
     The stream is closed after aBlock has been evaluated.
     Attributes may be the mime type (key #MIME)

     If doCreate is true, a nonExistent directory will be created.
     If doAtomic is true, files will appear atomically, by using
        an intermediate file theat will be renamed"

    |stream fileName toFileName|

    fileName := self asFilename.
    toFileName := fileName.
    doAtomic ifTrue:[
        fileName isDirectory ifFalse:[
            toFileName := fileName directory.
        ].
        toFileName := toFileName construct:'.transferFile'.
    ].
    [
        Stream streamErrorSignal handle:[:ex|
            doCreate ifFalse:[
                ex reject
            ].    
            fileName directory recursiveMakeDirectory.
            self exists ifTrue:[ |infoStream|
                infoStream := '' writeStream.
                self publicPrintOn:infoStream.
                self error:('Local write: Datei %1 already exists!!' bindWith:infoStream contents).
            ].
            stream := toFileName writeStream.
        ] do:[
            self exists ifTrue:[ |infoStream|
                infoStream := '' writeStream.
                self publicPrintOn:infoStream.
                self error:('Local write: Datei %1 already exists!!' bindWith:infoStream contents).
            ].
            stream := toFileName writeStream.
        ].
        aBlock value:stream value:self class attributes.
        stream close.
        doAtomic ifTrue:[
            toFileName moveTo:fileName.
        ]
    ] ifCurtailed:[
        stream notNil ifTrue:[stream close]
    ].

    "
        (URI fromString:'file:/home/tm/tmp') 
            readStreamsDo:[:stream :attributes| 
                Transcript showCR:(attributes at:#MIME).
                Transcript showCR:(stream isWritable).
            ].
    "
! !

!FileURI class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic2/FileURI.st,v 1.9 2003-07-24 09:29:43 tm Exp $'
! !