Eskil

Diff
Login

Differences From Artifact [106ffb8333]:

To Artifact [a4428b36b2]:


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
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
    namespace eval fossil {
        variable mpoints {}
    variable mpoints {}
    namespace eval fossil {
    }
    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
    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
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::fossil::Vfs]
    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 mpoints
    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 mpoints
    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
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::svn::Vfs]
    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 mpoints
    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
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
}

# 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"

# Extract file data from Fossil revision
    set origroot [dict get $mpoints $root origroot]
    set finfo [dict get $mpoints $root finfo]

proc vcsvfs::fossil::openFile {rootD relative} {
    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 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]]
        }
        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]} {
    #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"]
                # 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]
    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 $res
        }
    return $mtime
}
        createdirectory - deletefile - removedirectory - utime { 
            # Read-only, always error
        }

    }
    vfs::filesystem posixerror $::vfs::posix(EACCES)
    return -code error $::vfs::posix(EACCES)
# 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::svn::Vfs {subcmd root relative actual args} {
proc vcsvfs::Vfs {subcmd root relative actual args} {
    variable mpoints
    #puts "\nsvnVfs called:"
    #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 $mpoints $root origroot]
    set finfo [dict get $mpoints $root finfo]
    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
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)
            }

            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

            return [vcsvfs::${vcstype}::openFile $rootD $relative]
            #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 mtime [vcsvfs::${vcstype}::mTime \
                    set str [dict get $finfor mtimestr]
                                       [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 { 
        createdirectory - deletefile - removedirectory - utime {
            # Read-only, always error
        }
    }
    vfs::filesystem posixerror $::vfs::posix(EACCES)
    return -code error $::vfs::posix(EACCES)
}