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)
}
|
︙ | | | ︙ | |