Eskil

Check-in [1235042aab]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Refactored vcsvfs to get common code separate
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 1235042aabfacc1eb203f3fe1a7c8118dfd0072f
User & Date: peter 2014-11-18 00:02:48.068
Context
2014-11-18
16:25
Adjusted download page for 2.6.7 check-in: 4036613cfd user: peter tags: trunk
00:02
Refactored vcsvfs to get common code separate check-in: 1235042aab user: peter tags: trunk
2014-11-17
21:47
Get better status update in dirs while scanning check-in: 92b91d7d35 user: peter tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/vcsvfs.tcl.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#----------------------------------------------------------------------
#  Virtual File System for Verision Control Systems
#
#  Copyright (c) 2014, Peter Spjuth
#
#  License for vcsvfs package: Same as for Tcl
#----------------------------------------------------------------------

package require vfs
package provide vcsvfs 0.1

namespace eval vcsvfs {
    variable DataRefChan
    namespace eval fossil {
        variable mpoints {}

    }
    namespace eval svn {
        variable mpoints {}
    }
}

# Create a Virtual File System showing a revision of a fossil checkout
#
# dir: Directory in a fossil checkout
# rev: Revision to mount
#
# Returns: path to the generated VFS
proc vcsvfs::fossil::mount {dir rev} {
    variable mpoints
    set dir [file normalize $dir]

    # Fossil command must be run within the dir, so temporarily change pwd
    set oldpwd [pwd]
    cd $dir

    # The mount point will always be at the fossil root, even if













<
|
>


<










|







1
2
3
4
5
6
7
8
9
10
11
12
13

14
15
16
17

18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#----------------------------------------------------------------------
#  Virtual File System for Verision Control Systems
#
#  Copyright (c) 2014, Peter Spjuth
#
#  License for vcsvfs package: Same as for Tcl
#----------------------------------------------------------------------

package require vfs
package provide vcsvfs 0.1

namespace eval vcsvfs {
    variable DataRefChan

    variable mpoints {}
    namespace eval fossil {
    }
    namespace eval svn {

    }
}

# Create a Virtual File System showing a revision of a fossil checkout
#
# dir: Directory in a fossil checkout
# rev: Revision to mount
#
# Returns: path to the generated VFS
proc vcsvfs::fossil::mount {dir rev} {
    variable ::vcsvfs::mpoints
    set dir [file normalize $dir]

    # Fossil command must be run within the dir, so temporarily change pwd
    set oldpwd [pwd]
    cd $dir

    # The mount point will always be at the fossil root, even if
81
82
83
84
85
86
87

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    # Generate a mount point.
    set tail [string range $dir [string length $root] end]
    set mountpoint "${root} ($rev)"

    dict set mpoints $mountpoint "finfo" $finfo
    dict set mpoints $mountpoint "origroot" $root
    dict set mpoints $mountpoint "rev" $rev

    vfs::filesystem mount $mountpoint [list vcsvfs::fossil::Vfs]

    set result $mountpoint$tail
    #puts $result
    #puts [dict size $finfo]
    #puts [dict get $finfo [lindex $finfo 0]]
    return $result
}

proc vcsvfs::fossil::unmount {dir} {
    variable mpoints
    # TBD: Find the mountpoint
    #dict unset mpoints $mountpoint
    #vfs::filesystem unmount $mountpoint
}

# Create a Virtual File System showing a revision of an SVN checkout
#
# dir: Directory in an SVN checkout
# rev: Revision to mount
#
# Returns: path to the generated VFS
proc vcsvfs::svn::mount {dir rev} {
    variable mpoints
    set dir [file normalize $dir]

    # Command must be run within the dir, so temporarily change pwd
    set oldpwd [pwd]
    cd $dir

    # The mount point will normally be at the wc root, even if







>
|









|












|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
    # Generate a mount point.
    set tail [string range $dir [string length $root] end]
    set mountpoint "${root} ($rev)"

    dict set mpoints $mountpoint "finfo" $finfo
    dict set mpoints $mountpoint "origroot" $root
    dict set mpoints $mountpoint "rev" $rev
    dict set mpoints $mountpoint "vcstype" fossil
    vfs::filesystem mount $mountpoint [list vcsvfs::Vfs]

    set result $mountpoint$tail
    #puts $result
    #puts [dict size $finfo]
    #puts [dict get $finfo [lindex $finfo 0]]
    return $result
}

proc vcsvfs::fossil::unmount {dir} {
    variable ::vcsvfs::mpoints
    # TBD: Find the mountpoint
    #dict unset mpoints $mountpoint
    #vfs::filesystem unmount $mountpoint
}

# Create a Virtual File System showing a revision of an SVN checkout
#
# dir: Directory in an SVN checkout
# rev: Revision to mount
#
# Returns: path to the generated VFS
proc vcsvfs::svn::mount {dir rev} {
    variable ::vcsvfs::mpoints
    set dir [file normalize $dir]

    # Command must be run within the dir, so temporarily change pwd
    set oldpwd [pwd]
    cd $dir

    # The mount point will normally be at the wc root, even if
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
    # Generate a mount point.
    set tail [string range $dir [string length $root] end]
    set mountpoint "${root} ($rev)"

    dict set mpoints $mountpoint "finfo" $finfo
    dict set mpoints $mountpoint "origroot" $root
    dict set mpoints $mountpoint "rev" $rev

    vfs::filesystem mount $mountpoint [list vcsvfs::svn::Vfs]

    set result $mountpoint$tail
    #puts $result
    #puts [dict size $finfo]
    #puts [dict get $finfo [lindex $finfo 0]]
    return $result
}

proc vcsvfs::svn::unmount {dir} {
    variable mpoints
    # TBD: Find the mountpoint
    #dict unset mpoints $mountpoint
    #vfs::filesystem unmount $mountpoint
}

# Handler for Reflected Channel
proc vcsvfs::DataRefChan {id cmd chId args} {







>
|









|







174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
    # Generate a mount point.
    set tail [string range $dir [string length $root] end]
    set mountpoint "${root} ($rev)"

    dict set mpoints $mountpoint "finfo" $finfo
    dict set mpoints $mountpoint "origroot" $root
    dict set mpoints $mountpoint "rev" $rev
    dict set mpoints $mountpoint "vcstype" svn
    vfs::filesystem mount $mountpoint [list vcsvfs::Vfs]

    set result $mountpoint$tail
    #puts $result
    #puts [dict size $finfo]
    #puts [dict get $finfo [lindex $finfo 0]]
    return $result
}

proc vcsvfs::svn::unmount {dir} {
    variable ::vcsvfs::mpoints
    # TBD: Find the mountpoint
    #dict unset mpoints $mountpoint
    #vfs::filesystem unmount $mountpoint
}

# Handler for Reflected Channel
proc vcsvfs::DataRefChan {id cmd chId args} {
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338

339
340
341
342
343
344
345
346
347
348
349

350


351
352
353
354
355
356
357
358
359

360




361
362
363
364
365
366
367
368
369
370
371
372
373

374
375

376
377
378
379
380
381
382
        if {[dict get $finfo $local isfile] && !$allowFile} continue
        if {[dict get $finfo $local isdir] && !$allowDir} continue
        lappend result [file join $actual $child]
    }
    return $result
}

# The handler for the mounted VFS
proc vcsvfs::fossil::Vfs {subcmd root relative actual args} {
    variable mpoints
    #puts "\nfossilVfs called:"
    #puts " Su $subcmd"
    #puts " Ro $root"
    #puts " Re $relative"
    #puts " Ac $actual"
    #puts " Ar $args"

    set origroot [dict get $mpoints $root origroot]
    set finfo [dict get $mpoints $root finfo]

    if {![dict exists $finfo $relative]} {
        # Unknown path
        vfs::filesystem posixerror $::vfs::posix(EACCES)
        return -code error $::vfs::posix(EACCES)
    }
    set finfor [dict get $finfo $relative]
    #puts " $finfor"

    switch $subcmd {
        access {
            set mode [vfs::accessMode [lindex $args 0]]
            # Only read supported
            if {$mode ne "R"} {
                vfs::filesystem posixerror $::vfs::posix(EACCES)
                return -code error $::vfs::posix(EACCES)
            }
            return
        }
        fileattributes {
            #set index [lindex $args 0]
            #set value [lindex $args 1]
            return
        }
        matchindirectory {
            return [vcsvfs::MatchInDirectory $finfo $relative $actual {*}$args]
        }
        open {
            set mode [lindex $args 0]
            if {$mode == {}} {set mode r}
            #set permissions [lindex $args 1]
            if {$mode ne "r"} {
                # Read only
                vfs::filesystem posixerror $::vfs::posix(EACCES)
                return -code error $::vfs::posix(EACCES)
            }

            set oldpwd [pwd]
            cd [dict get $mpoints $root "origroot"]
            set rev [dict get $mpoints $root rev]
            # Which way of extracting file data is best?
            # fossil finfo -p -r $rev $relative
            # set sha [dict get $finfor sha]
            # fossil artifact $sha
            # fossil cat $relative -r $rev
            # Read through a pipe to get a binary channel
            set chId [open [list |fossil cat $relative -r $rev] rb]
            #set data [read $chId]
            #close $chId
            #cd $oldpwd

            #set chId [vcsvfs::CreateDataRefChan $data]
            return [list $chId [list vcsvfs::ReadAllBeforeClose $chId]]
        }
        stat {
            set res [dict create dev 0 ino 0 "mode" 0 nlink 0 uid 0 gid 0 \
                             size 0 atime 0 mtime 0 ctime 0 type file]

            if {[dict get $finfor isdir]} {
                # TBD, fake mtime etc. for directory?
                dict set res type directory
            } else {
                if {![dict exists $finfor mtime]} {
                    set str [dict get $finfor mtimestr]
                    # TBD parse to mtime correct?
                    set mtime [clock scan $str -gmt 1]
                    dict set finfor "mtime" $mtime
                    # Cache in main dictionary too
                    dict set mpoints $root "finfo" $relative "mtime" $mtime

                }


                dict set res "mtime" [dict get $finfor "mtime"]
                dict set res size  [dict get $finfor size]
            }
            return $res
        }
        createdirectory - deletefile - removedirectory - utime { 
            # Read-only, always error
        }
    }

    vfs::filesystem posixerror $::vfs::posix(EACCES)




    return -code error $::vfs::posix(EACCES)
}

# The handler for the mounted VFS
proc vcsvfs::svn::Vfs {subcmd root relative actual args} {
    variable mpoints
    #puts "\nsvnVfs called:"
    #puts " Su $subcmd"
    #puts " Ro $root"
    #puts " Re $relative"
    #puts " Ac $actual"
    #puts " Ar $args"


    set origroot [dict get $mpoints $root origroot]
    set finfo [dict get $mpoints $root finfo]


    if {![dict exists $finfo $relative]} {
        # Unknown path
        vfs::filesystem posixerror $::vfs::posix(EACCES)
        return -code error $::vfs::posix(EACCES)
    }
    set finfor [dict get $finfo $relative]







<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
>
|
<
|
|
|
|
|
|
|
|
|
>
|
>
>
|
|
<
|
|
<
<
|
<
>
|
>
>
>
>
|



|

|






>
|
|
>







264
265
266
267
268
269
270









271


272




































273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309

310
311


312

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
        if {[dict get $finfo $local isfile] && !$allowFile} continue
        if {[dict get $finfo $local isdir] && !$allowDir} continue
        lappend result [file join $actual $child]
    }
    return $result
}










# Extract file data from Fossil revision


proc vcsvfs::fossil::openFile {rootD relative} {




































    set oldpwd [pwd]
    cd [dict get $rootD "origroot"]
    set rev [dict get $rootD rev]
    # Which way of extracting file data is best?
    # fossil finfo -p -r $rev $relative
    # set sha [dict get $finfor sha]
    # fossil artifact $sha
    # fossil cat $relative -r $rev
    # Read through a pipe to get a binary channel
    set chId [open [list |fossil cat $relative -r $rev] rb]
    #set data [read $chId]
    #close $chId
    cd $oldpwd

    #set chId [vcsvfs::CreateDataRefChan $data]
    return [list $chId [list vcsvfs::ReadAllBeforeClose $chId]]
}

# Extract file data from Subversion revision
proc vcsvfs::svn::openFile {rootD relative} {
    set oldpwd [pwd]
    cd [dict get $rootD "origroot"]

    set rev [dict get $rootD rev]
    # Read through a pipe to get a binary channel
    set chId [open [list |svn cat -r $rev $relative] rb]
    #set data [read $chId]
    #close $chId
    cd $oldpwd

    #set chId [vcsvfs::CreateDataRefChan $data]
    return [list $chId [list vcsvfs::ReadAllBeforeClose $chId]]
}

# Parse a time string from Fossil
proc vcsvfs::fossil::mTime {mtimestr} {
    # TBD parse to mtime correct?
    set mtime [clock scan $mtimestr -gmt 1]

    return $mtime
}




# Parse a time string from Subversion
proc vcsvfs::svn::mTime {mtimestr} {
    # TBD parse to mtime correct?
    # Remove any decimals from time string
    regsub {\.\d+Z} $mtimestr "" mtimestr
    set mtime [clock scan $mtimestr -gmt 1]
    return $mtime
}

# The handler for the mounted VFS
proc vcsvfs::Vfs {subcmd root relative actual args} {
    variable mpoints
    #puts "\nVfs called:"
    #puts " Su $subcmd"
    #puts " Ro $root"
    #puts " Re $relative"
    #puts " Ac $actual"
    #puts " Ar $args"

    set rootD [dict get $mpoints $root]
    set origroot [dict get $rootD origroot]
    set finfo [dict get $rootD finfo]
    set vcstype [dict get $rootD vcstype]

    if {![dict exists $finfo $relative]} {
        # Unknown path
        vfs::filesystem posixerror $::vfs::posix(EACCES)
        return -code error $::vfs::posix(EACCES)
    }
    set finfor [dict get $finfo $relative]
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432

433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
            #set permissions [lindex $args 1]
            if {$mode ne "r"} {
                # Read only
                vfs::filesystem posixerror $::vfs::posix(EACCES)
                return -code error $::vfs::posix(EACCES)
            }

            set oldpwd [pwd]
            cd [dict get $mpoints $root "origroot"]
            set rev [dict get $mpoints $root rev]
            # Read through a pipe to get a binary channel
            set chId [open [list |svn cat -r $rev $relative] rb]
            #set data [read $chId]
            #close $chId
            #cd $oldpwd

            #set chId [vcsvfs::CreateDataRefChan $data]
            return [list $chId [list vcsvfs::ReadAllBeforeClose $chId]]
        }
        stat {
            set res [dict create dev 0 ino 0 "mode" 0 nlink 0 uid 0 gid 0 \
                             size 0 atime 0 mtime 0 ctime 0 type file]
            if {[dict get $finfor isdir]} {
                # TBD, fake mtime etc. for directory?
                dict set res type directory
            } else {
                if {![dict exists $finfor mtime]} {

                    set str [dict get $finfor mtimestr]
                    # TBD parse to mtime correct?
                    # Remove any decimals from time string
                    regsub {\.\d+Z} $str "" str
                    set mtime [clock scan $str -gmt 1]
                    dict set finfor "mtime" $mtime
                    # Cache in main dictionary too
                    dict set mpoints $root "finfo" $relative "mtime" $mtime
                }
                dict set res "mtime" [dict get $finfor "mtime"]
                dict set res size  [dict get $finfor size]
            }
            return $res
        }
        createdirectory - deletefile - removedirectory - utime { 
            # Read-only, always error
        }
    }
    vfs::filesystem posixerror $::vfs::posix(EACCES)
    return -code error $::vfs::posix(EACCES)
}








<
<
<
<
<
<
<
<
|
<
<





<



>
|
<
<
<
<









|







366
367
368
369
370
371
372








373


374
375
376
377
378

379
380
381
382
383




384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
            #set permissions [lindex $args 1]
            if {$mode ne "r"} {
                # Read only
                vfs::filesystem posixerror $::vfs::posix(EACCES)
                return -code error $::vfs::posix(EACCES)
            }









            return [vcsvfs::${vcstype}::openFile $rootD $relative]


        }
        stat {
            set res [dict create dev 0 ino 0 "mode" 0 nlink 0 uid 0 gid 0 \
                             size 0 atime 0 mtime 0 ctime 0 type file]
            if {[dict get $finfor isdir]} {

                dict set res type directory
            } else {
                if {![dict exists $finfor mtime]} {
                    set mtime [vcsvfs::${vcstype}::mTime \
                                       [dict get $finfor mtimestr]]




                    dict set finfor "mtime" $mtime
                    # Cache in main dictionary too
                    dict set mpoints $root "finfo" $relative "mtime" $mtime
                }
                dict set res "mtime" [dict get $finfor "mtime"]
                dict set res size  [dict get $finfor size]
            }
            return $res
        }
        createdirectory - deletefile - removedirectory - utime {
            # Read-only, always error
        }
    }
    vfs::filesystem posixerror $::vfs::posix(EACCES)
    return -code error $::vfs::posix(EACCES)
}