Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pyfs
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
pyfs
Commits
e69d8929
Commit
e69d8929
authored
Dec 16, 2010
by
willmcgugan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Command improvements
parent
a143bd9a
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
232 additions
and
101 deletions
+232
-101
fs/browsewin.py
+30
-12
fs/commands/fscp.py
+1
-1
fs/commands/fsls.py
+24
-17
fs/commands/fsmkdir.py
+1
-1
fs/commands/fsmount.py
+1
-1
fs/commands/fsserve.py
+1
-1
fs/commands/fstree.py
+16
-9
fs/commands/runner.py
+51
-24
fs/ftpfs.py
+12
-0
fs/opener.py
+45
-8
fs/sftpfs.py
+47
-22
fs/wrapfs/subfs.py
+3
-5
No files found.
fs/browsewin.py
View file @
e69d8929
...
...
@@ -14,12 +14,13 @@ Requires wxPython.
import
wx
import
wx.gizmos
import
base
as
fs
from
fs.path
import
isdotfile
,
pathsplit
from
fs.errors
import
FSError
class
InfoFrame
(
wx
.
Frame
):
def
__init__
(
self
,
path
,
desc
,
info
):
wx
.
Frame
.
__init__
(
self
,
None
,
-
1
,
style
=
wx
.
DEFAULT_FRAME_STYLE
,
size
=
(
500
,
500
))
def
__init__
(
self
,
pa
rent
,
pa
th
,
desc
,
info
):
wx
.
Frame
.
__init__
(
self
,
parent
,
-
1
,
style
=
wx
.
DEFAULT_FRAME_STYLE
,
size
=
(
500
,
500
))
self
.
SetTitle
(
"FS Object info -
%
s (
%
s)"
%
(
path
,
desc
))
...
...
@@ -34,19 +35,22 @@ class InfoFrame(wx.Frame):
self
.
list_ctrl
.
SetColumnWidth
(
0
,
190
)
self
.
list_ctrl
.
SetColumnWidth
(
1
,
300
)
for
key
in
keys
:
self
.
list_ctrl
.
Append
((
key
,
str
(
info
.
get
(
key
))))
for
key
in
sorted
(
keys
,
key
=
lambda
k
:
k
.
lower
()):
self
.
list_ctrl
.
Append
((
key
,
unicode
(
info
.
get
(
key
))))
self
.
Center
()
class
BrowseFrame
(
wx
.
Frame
):
def
__init__
(
self
,
fs
):
def
__init__
(
self
,
fs
,
hide_dotfiles
=
False
):
wx
.
Frame
.
__init__
(
self
,
None
,
size
=
(
1000
,
600
))
self
.
fs
=
fs
self
.
SetTitle
(
"FS Browser - "
+
str
(
fs
))
self
.
hide_dotfiles
=
hide_dotfiles
self
.
SetTitle
(
"FS Browser - "
+
unicode
(
fs
))
self
.
tree
=
wx
.
gizmos
.
TreeListCtrl
(
self
,
-
1
,
style
=
wx
.
TR_DEFAULT_STYLE
|
wx
.
TR_HIDE_ROOT
)
...
...
@@ -98,7 +102,19 @@ class BrowseFrame(wx.Frame):
if
item_data
[
'expanded'
]:
return
paths
=
[(
self
.
fs
.
isdir
(
p
),
p
)
for
p
in
self
.
fs
.
listdir
(
path
,
absolute
=
True
)]
try
:
paths
=
(
[(
True
,
p
)
for
p
in
self
.
fs
.
listdir
(
path
,
absolute
=
True
,
dirs_only
=
True
)]
+
[(
False
,
p
)
for
p
in
self
.
fs
.
listdir
(
path
,
absolute
=
True
,
files_only
=
True
)]
)
except
FSError
,
e
:
msg
=
"Failed to get directory listing for
%
s
\n\n
The following error was reported:
\n\n
%
s"
%
(
path
,
e
)
wx
.
MessageDialog
(
self
,
msg
,
"Error listing directory"
,
wx
.
OK
)
.
ShowModal
()
paths
=
[]
#paths = [(self.fs.isdir(p), p) for p in self.fs.listdir(path, absolute=True)]
if
self
.
hide_dotfiles
:
paths
=
[
p
for
p
in
paths
if
not
isdotfile
(
p
[
1
])]
if
not
paths
:
#self.tree.SetItemHasChildren(item_id, False)
...
...
@@ -109,7 +125,7 @@ class BrowseFrame(wx.Frame):
for
is_dir
,
new_path
in
paths
:
name
=
fs
.
pathsplit
(
new_path
)[
-
1
]
name
=
pathsplit
(
new_path
)[
-
1
]
new_item
=
self
.
tree
.
AppendItem
(
item_id
,
name
,
data
=
wx
.
TreeItemData
({
'path'
:
new_path
,
'expanded'
:
False
}))
...
...
@@ -157,20 +173,22 @@ class BrowseFrame(wx.Frame):
path
=
item_data
[
"path"
]
info
=
self
.
fs
.
getinfo
(
path
)
info_frame
=
InfoFrame
(
path
,
self
.
fs
.
desc
(
path
),
info
)
info_frame
=
InfoFrame
(
self
,
path
,
self
.
fs
.
desc
(
path
),
info
)
info_frame
.
Show
()
info_frame
.
CenterOnParent
()
def
browse
(
fs
):
def
browse
(
fs
,
hide_dotfiles
=
False
):
"""Displays a window containing a tree control that displays an FS
object. Double-click a file/folder to display extra info.
:param fs: A filesystem object
:param hide_fotfiles: If True, files and folders that begin with a dot will be hidden
"""
app
=
wx
.
PySimpleApp
()
frame
=
BrowseFrame
(
fs
)
frame
=
BrowseFrame
(
fs
,
hide_dotfiles
=
True
)
frame
.
Show
()
app
.
MainLoop
()
...
...
fs/commands/fscp.py
View file @
e69d8929
...
...
@@ -74,7 +74,7 @@ Copy SOURCE to DESTINATION"""
srcs
=
args
[:
-
1
]
dst
=
args
[
-
1
]
dst_fs
,
dst_path
=
self
.
open_fs
(
dst
,
writeable
=
True
,
create
=
True
)
dst_fs
,
dst_path
=
self
.
open_fs
(
dst
,
writeable
=
True
,
create
_dir
=
True
)
if
dst_path
is
not
None
and
dst_fs
.
isfile
(
dst_path
):
self
.
error
(
'Destination must be a directory
\n
'
)
...
...
fs/commands/fsls.py
View file @
e69d8929
...
...
@@ -17,7 +17,9 @@ List contents of [PATH]"""
optparse
.
add_option
(
'-u'
,
'--full'
,
dest
=
'fullpath'
,
action
=
"store_true"
,
default
=
False
,
help
=
"output full path"
,
metavar
=
"FULL"
)
optparse
.
add_option
(
'-s'
,
'--syspath'
,
dest
=
'syspath'
,
action
=
"store_true"
,
default
=
False
,
help
=
"output system path"
,
metavar
=
"SYSPATH"
)
help
=
"output system path (if one exists)"
,
metavar
=
"SYSPATH"
)
optparse
.
add_option
(
'-r'
,
'--url'
,
dest
=
'url'
,
action
=
"store_true"
,
default
=
False
,
help
=
"output URL in place of path (if one exists)"
,
metavar
=
"URL"
)
optparse
.
add_option
(
'-d'
,
'--dirsonly'
,
dest
=
'dirsonly'
,
action
=
"store_true"
,
default
=
False
,
help
=
"list directories only"
,
metavar
=
"DIRSONLY"
)
optparse
.
add_option
(
'-f'
,
'--filesonly'
,
dest
=
'filesonly'
,
action
=
"store_true"
,
default
=
False
,
...
...
@@ -52,30 +54,36 @@ List contents of [PATH]"""
if
not
options
.
dirsonly
:
file_paths
.
append
(
path
)
else
:
if
not
options
.
filesonly
:
if
not
options
.
filesonly
:
dir_paths
+=
fs
.
listdir
(
path
,
wildcard
=
wildcard
,
full
=
options
.
fullpath
,
full
=
options
.
fullpath
or
options
.
url
,
dirs_only
=
True
)
if
not
options
.
dirsonly
:
file_paths
+=
fs
.
listdir
(
path
,
wildcard
=
wildcard
,
full
=
options
.
fullpath
,
full
=
options
.
fullpath
or
options
.
url
,
files_only
=
True
)
try
:
for
fs
in
fs_used
:
for
fs
in
fs_used
:
try
:
fs
.
close
()
except
FSError
:
pass
except
FSError
:
pass
if
options
.
syspath
:
dir_paths
=
[
fs
.
getsyspath
(
path
,
allow_none
=
True
)
or
path
for
path
in
dir_paths
]
file_paths
=
[
fs
.
getsyspath
(
path
,
allow_none
=
True
)
or
path
for
path
in
file_paths
]
# Path without a syspath, just won't be displayed
dir_paths
=
filter
(
None
,
[
fs
.
getsyspath
(
path
,
allow_none
=
True
)
for
path
in
dir_paths
])
file_paths
=
filter
(
None
,
[
fs
.
getsyspath
(
path
,
allow_none
=
True
)
for
path
in
file_paths
])
if
options
.
url
:
# Path without a syspath, just won't be displayed
dir_paths
=
filter
(
None
,
[
fs
.
getpathurl
(
path
,
allow_none
=
True
)
for
path
in
dir_paths
])
file_paths
=
filter
(
None
,
[
fs
.
getpathurl
(
path
,
allow_none
=
True
)
for
path
in
file_paths
])
dirs
=
frozenset
(
dir_paths
)
paths
=
sorted
(
dir_paths
+
file_paths
,
key
=
lambda
p
:
p
.
lower
())
dirs
=
frozenset
(
dir_paths
)
paths
=
sorted
(
dir_paths
+
file_paths
,
key
=
lambda
p
:
p
.
lower
())
if
not
options
.
all
:
paths
=
[
path
for
path
in
paths
if
not
isdotfile
(
path
)]
...
...
@@ -129,9 +137,9 @@ List contents of [PATH]"""
if
options
.
long
:
for
path
in
paths
:
if
path
in
dirs
:
output
(
self
.
wrap_dirname
(
path
)
+
'
\n
'
)
output
(
(
self
.
wrap_dirname
(
path
),
'
\n
'
)
)
else
:
output
(
self
.
wrap_filename
(
path
)
+
'
\n
'
)
output
(
(
self
.
wrap_filename
(
path
),
'
\n
'
)
)
else
:
terminal_width
=
self
.
terminal_width
...
...
@@ -158,8 +166,7 @@ List contents of [PATH]"""
num_cols
-=
1
num_cols
=
max
(
1
,
num_cols
)
columns
=
columnize
(
paths
,
num_cols
)
output
(
condense_columns
(
columns
))
output
(
'
\n
'
)
output
((
condense_columns
(
columns
),
'
\n
'
))
def
run
():
return
FSls
()
.
run
()
...
...
fs/commands/fsmkdir.py
View file @
e69d8929
...
...
@@ -14,7 +14,7 @@ Make a directory"""
def
do_run
(
self
,
options
,
args
):
for
fs_url
in
args
:
fs
,
path
=
self
.
open_fs
(
fs_url
,
create
=
True
)
fs
,
path
=
self
.
open_fs
(
fs_url
,
create
_dir
=
True
)
def
run
():
return
FSMkdir
()
.
run
()
...
...
fs/commands/fsmount.py
View file @
e69d8929
...
...
@@ -54,7 +54,7 @@ Mounts a file system on a system path"""
if
platform
.
system
()
==
'Windows'
:
pass
else
:
fs
,
path
=
self
.
open_fs
(
fs_url
,
create
=
True
)
fs
,
path
=
self
.
open_fs
(
fs_url
,
create
_dir
=
True
)
if
path
:
if
not
fs
.
isdir
(
path
):
self
.
error
(
'
%
s is not a directory on
%
s'
%
(
fs_url
.
fs
))
...
...
fs/commands/fsserve.py
View file @
e69d8929
...
...
@@ -8,7 +8,7 @@ from fs.utils import print_fs
class
FSServe
(
Command
):
"""fsserve [OPTION]... [PATH]
usage
=
"""fsserve [OPTION]... [PATH]
Serves the contents of PATH with one of a number of methods"""
def
get_optparse
(
self
):
...
...
fs/commands/fstree.py
View file @
e69d8929
...
...
@@ -15,6 +15,8 @@ Recursively display the contents of PATH in an ascii tree"""
optparse
=
super
(
FSTree
,
self
)
.
get_optparse
()
optparse
.
add_option
(
'-l'
,
'--level'
,
dest
=
'depth'
,
type
=
"int"
,
default
=
5
,
help
=
"Descend only LEVEL directories deep"
,
metavar
=
"LEVEL"
)
optparse
.
add_option
(
'-g'
,
'--gui'
,
dest
=
'gui'
,
action
=
'store_true'
,
default
=
False
,
help
=
"browse the tree with a gui"
)
optparse
.
add_option
(
'-a'
,
'--all'
,
dest
=
'all'
,
action
=
'store_true'
,
default
=
False
,
help
=
"do not hide dot files"
)
optparse
.
add_option
(
'-d'
,
'--dirsfirst'
,
dest
=
'dirsfirst'
,
action
=
'store_true'
,
default
=
False
,
...
...
@@ -26,18 +28,23 @@ Recursively display the contents of PATH in an ascii tree"""
if
not
args
:
args
=
[
'.'
]
for
fs
,
path
,
is_dir
in
self
.
get_resources
(
args
,
single
=
True
):
if
path
is
not
None
:
fs
.
opendir
(
path
)
for
fs
,
path
,
is_dir
in
self
.
get_resources
(
args
,
single
=
True
):
if
not
is_dir
:
self
.
error
(
u"'
%
s' is not a dir
\n
"
%
path
)
return
1
print_fs
(
fs
,
path
or
''
,
file_out
=
self
.
output_file
,
max_levels
=
options
.
depth
,
terminal_colors
=
self
.
is_terminal
(),
hide_dotfiles
=
not
options
.
all
,
dirs_first
=
options
.
dirsfirst
)
fs
.
cache_hint
(
True
)
if
options
.
gui
:
from
fs.browsewin
import
browse
if
path
:
fs
=
fs
.
opendir
(
path
)
browse
(
fs
,
hide_dotfiles
=
not
options
.
all
)
else
:
print_fs
(
fs
,
path
or
''
,
file_out
=
self
.
output_file
,
max_levels
=
options
.
depth
,
terminal_colors
=
self
.
is_terminal
(),
hide_dotfiles
=
not
options
.
all
,
dirs_first
=
options
.
dirsfirst
)
def
run
():
return
FSTree
()
.
run
()
...
...
fs/commands/runner.py
View file @
e69d8929
...
...
@@ -5,7 +5,7 @@ from fs.errors import FSError
from
fs.path
import
splitext
,
pathsplit
,
isdotfile
,
iswildcard
import
platform
from
collections
import
defaultdict
import
re
if
platform
.
system
()
==
'Linux'
:
def
getTerminalSize
():
...
...
@@ -51,8 +51,11 @@ class Command(object):
self
.
encoding
=
getattr
(
self
.
output_file
,
'encoding'
,
'utf-8'
)
or
'utf-8'
self
.
verbosity_level
=
0
self
.
terminal_colors
=
not
sys
.
platform
.
startswith
(
'win'
)
and
self
.
is_terminal
()
w
,
h
=
getTerminalSize
()
self
.
terminal_width
=
w
if
self
.
is_terminal
():
w
,
h
=
getTerminalSize
()
self
.
terminal_width
=
w
else
:
self
.
terminal_width
=
80
self
.
name
=
self
.
__class__
.
__name__
.
lower
()
def
is_terminal
(
self
):
...
...
@@ -74,7 +77,9 @@ class Command(object):
def
wrap_filename
(
self
,
fname
):
fname
=
_unicode
(
fname
)
if
not
self
.
terminal_colors
:
return
fname
return
fname
if
'://'
in
fname
:
return
fname
if
'.'
in
fname
:
name
,
ext
=
splitext
(
fname
)
fname
=
u'
%
s
\x1b
[36m
%
s
\x1b
[0m'
%
(
name
,
ext
)
...
...
@@ -88,16 +93,35 @@ class Command(object):
return
text
return
u'
\x1b
[2m
%
s
\x1b
[0m'
%
text
def
wrap_link
(
self
,
text
):
if
not
self
.
terminal_colors
:
return
text
return
u'
\x1b
[1;33m
%
s
\x1b
[0m'
%
text
def
wrap_strong
(
self
,
text
):
if
not
self
.
terminal_colors
:
return
text
return
u'
\x1b
[1m
%
s
\x1b
[0m'
%
text
def
wrap_table_header
(
self
,
name
):
if
not
self
.
terminal_colors
:
return
name
return
'
\x1b
[1;32m
%
s
\x1b
[0m'
%
name
def
open_fs
(
self
,
fs_url
,
writeable
=
False
,
create
=
False
):
def
highlight_fsurls
(
self
,
text
):
if
not
self
.
terminal_colors
:
return
text
re_fs
=
r'(\S*?://\S*)'
def
repl
(
matchobj
):
fs_url
=
matchobj
.
group
(
0
)
return
self
.
wrap_link
(
fs_url
)
return
re
.
sub
(
re_fs
,
repl
,
text
)
def
open_fs
(
self
,
fs_url
,
writeable
=
False
,
create_dir
=
False
):
try
:
fs
,
path
=
opener
.
parse
(
fs_url
,
writeable
=
writeable
,
create_dir
=
create
)
fs
,
path
=
opener
.
parse
(
fs_url
,
writeable
=
writeable
,
create_dir
=
create
_dir
)
except
OpenerError
,
e
:
self
.
error
(
str
(
e
)
+
'
\n
'
)
self
.
error
(
str
(
e
)
,
'
\n
'
)
sys
.
exit
(
1
)
fs
.
cache_hint
(
True
)
return
fs
,
path
...
...
@@ -168,12 +192,15 @@ class Command(object):
return
text
def
output
(
self
,
msg
,
verbose
=
False
):
if
verbose
and
not
self
.
verbose
:
return
self
.
output_file
.
write
(
self
.
text_encode
(
msg
))
def
output
(
self
,
msgs
,
verbose
=
False
):
if
verbose
and
not
self
.
verbose
:
return
if
isinstance
(
msgs
,
basestring
):
msgs
=
(
msgs
,)
for
msg
in
msgs
:
self
.
output_file
.
write
(
self
.
text_encode
(
msg
))
def
output_table
(
self
,
table
,
col_process
=
None
,
verbose
=
False
):
if
verbose
and
not
self
.
verbose
:
...
...
@@ -199,8 +226,9 @@ class Command(object):
lines
.
append
(
self
.
text_encode
(
'
%
s
\n
'
%
' '
.
join
(
out_col
)
.
rstrip
()))
self
.
output
(
''
.
join
(
lines
))
def
error
(
self
,
msg
):
self
.
error_file
.
write
(
'
%
s:
%
s'
%
(
self
.
name
,
self
.
text_encode
(
msg
)))
def
error
(
self
,
*
msgs
):
for
msg
in
msgs
:
self
.
error_file
.
write
(
'
%
s:
%
s'
%
(
self
.
name
,
self
.
text_encode
(
msg
)))
def
get_optparse
(
self
):
optparse
=
OptionParser
(
usage
=
self
.
usage
,
version
=
self
.
version
)
...
...
@@ -229,23 +257,23 @@ class Command(object):
for
line
in
lines
:
words
=
[]
line_len
=
0
for
word
in
line
.
split
():
for
word
in
line
.
split
():
if
word
==
'*'
:
word
=
' *'
if
line_len
+
len
(
word
)
>
self
.
terminal_width
:
self
.
output
(
' '
.
join
(
words
))
self
.
output
(
'
\n
'
)
self
.
output
((
self
.
highlight_fsurls
(
' '
.
join
(
words
)),
'
\n
'
))
del
words
[:]
line_len
=
0
words
.
append
(
word
)
line_len
+=
len
(
word
)
+
1
if
words
:
self
.
output
(
' '
.
join
(
words
))
self
.
output
(
self
.
highlight_fsurls
(
' '
.
join
(
words
)
))
self
.
output
(
'
\n
'
)
for
names
,
desc
in
opener_table
:
self
.
output
(
'
\n
'
)
for
names
,
desc
in
opener_table
:
self
.
output
(
(
'-'
*
self
.
terminal_width
,
'
\n
'
))
proto
=
', '
.
join
([
n
+
'://'
for
n
in
names
])
self
.
output
(
self
.
wrap_dirname
(
'[
%
s]'
%
proto
))
self
.
output
(
'
\n
'
)
self
.
output
((
self
.
wrap_dirname
(
'[
%
s]'
%
proto
),
'
\n\n
'
))
if
not
desc
.
strip
():
desc
=
"No information available"
wrap_line
(
desc
)
...
...
@@ -280,8 +308,7 @@ class Command(object):
if
options
.
debug
:
raise
return
1
if
__name__
==
"__main__"
:
command
=
Command
()
...
...
fs/ftpfs.py
View file @
e69d8929
...
...
@@ -1035,6 +1035,15 @@ class FTPFS(FS):
pass
self
.
closed
=
True
def
getpathurl
(
self
,
path
,
allow_none
=
False
):
path
=
normpath
(
path
)
credentials
=
'
%
s:
%
s'
%
(
self
.
user
,
self
.
passwd
)
if
credentials
==
':'
:
url
=
'ftp://
%
s
%
s'
%
(
self
.
host
.
rstrip
(
'/'
),
abspath
(
path
))
else
:
url
=
'ftp://
%
s@
%
s
%
s'
%
(
credentials
,
self
.
host
.
rstrip
(
'/'
),
abspath
(
path
))
return
url
@ftperrors
def
open
(
self
,
path
,
mode
=
'r'
):
mode
=
mode
.
lower
()
...
...
@@ -1249,6 +1258,9 @@ class FTPFS(FS):
@ftperrors
def
desc
(
self
,
path
):
url
=
self
.
getpathurl
(
path
,
allow_none
=
True
)
if
url
:
return
url
dirlist
,
fname
=
self
.
_check_path
(
path
)
if
fname
not
in
dirlist
:
raise
ResourceNotFoundError
(
path
)
...
...
fs/opener.py
View file @
e69d8929
...
...
@@ -210,7 +210,13 @@ class Opener(object):
class
OSFSOpener
(
Opener
):
names
=
[
'osfs'
,
'file'
]
desc
=
"OS filesystem opener, works with any valid system path. This is the default opener and will be used if you don't indicate which opener to use."
desc
=
"""OS filesystem opener, works with any valid system path. This is the default opener and will be used if you don't indicate which opener to use.
examples:
* file://relative/foo/bar/baz.txt (opens a relative file)
* file:///home/user (opens a directory from a absolute path)
* osfs://~/ (open the user's home directory)
* foo/bar.baz (file:// is the default opener)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -226,7 +232,12 @@ class OSFSOpener(Opener):
class
ZipOpener
(
Opener
):
names
=
[
'zip'
,
'zip64'
]
desc
=
"Opens zip files. Use zip64 for > 2 megabyte zip files, if you have a 64 bit processor.
\n
e.g. zip://myzip"
desc
=
"""Opens zip files. Use zip64 for > 2 megabyte zip files, if you have a 64 bit processor.
examples:
* zip://myzip.zip (open a local zip file)
* zip://myzip.zip!foo/bar/insidezip.txt (reference a file insize myzip.zip)
* zip:ftp://ftp.example.org/myzip.zip (open a zip file stored on a ftp server)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -263,7 +274,11 @@ class ZipOpener(Opener):
class
RPCOpener
(
Opener
):
names
=
[
'rpc'
]
desc
=
"An opener for filesystems server over RPC (see the fsserve command). e.g. rpc://127.0.0.1"
desc
=
"""An opener for filesystems server over RPC (see the fsserve command).
examples:
rpc://127.0.0.1:8000 (opens a RPC server running on local host, port 80)
rpc://www.example.org (opens an RPC server on www.example.org, default port 80)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -284,7 +299,11 @@ class RPCOpener(Opener):
class
FTPOpener
(
Opener
):
names
=
[
'ftp'
]
desc
=
"An opener for FTP (File Transfer Protocl) servers. e.g. ftp://ftp.mozilla.org"
desc
=
"""An opener for FTP (File Transfer Protocl) server
examples:
* ftp://ftp.mozilla.org (opens the root of ftp.mozilla.org)
* ftp://ftp.example.org/foo/bar (opens /foo/bar on ftp.mozilla.org)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -316,7 +335,11 @@ class FTPOpener(Opener):
class
SFTPOpener
(
Opener
):
names
=
[
'sftp'
]
desc
=
"An opener for SFTP (Secure File Transfer Protocol) servers"
desc
=
"""An opener for SFTP (Secure File Transfer Protocol) servers
examples:
* sftp://username:password@example.org (opens sftp server example.org with username and password
* sftp://example.org (opens example.org with public key authentication)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -367,7 +390,13 @@ class SFTPOpener(Opener):
class
MemOpener
(
Opener
):
names
=
[
'mem'
,
'ram'
]
desc
=
"""Creates an in-memory filesystem (very fast but contents will disappear on exit)."""
desc
=
"""Creates an in-memory filesystem (very fast but contents will disappear on exit).
Useful for creating a fast temporary filesystem for serving or mounting with fsserve or fsmount.
NB: If you user fscp or fsmv to copy/move files here, you are effectively deleting them!
examples:
* mem:// (opens a new memory filesystem)
* mem://foo/bar (opens a new memory filesystem with subdirectory /foo/bar) """
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -380,7 +409,10 @@ class MemOpener(Opener):
class
DebugOpener
(
Opener
):
names
=
[
'debug'
]
desc
=
"For developer -- adds debugging information to output. To use prepend an exisiting opener with debug: e.g debug:ftp://ftp.mozilla.org"
desc
=
"""For developers -- adds debugging information to output.
example:
* debug:ftp://ftp.mozilla.org (displays details of calls made to a ftp filesystem)"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
@@ -398,7 +430,12 @@ class DebugOpener(Opener):
class
TempOpener
(
Opener
):
names
=
[
'temp'
]
desc
=
"Creates a temporary filesystem, that is erased on exit."
desc
=
"""Creates a temporary filesystem, that is erased on exit.
Probably only useful for mounting or serving.
NB: If you user fscp or fsmv to copy/move files here, you are effectively deleting them!
example:
* temp://"""
@classmethod
def
get_fs
(
cls
,
registry
,
fs_name
,
fs_name_params
,
fs_path
,
writeable
,
create_dir
):
...
...
fs/sftpfs.py
View file @
e69d8929
...
...
@@ -93,6 +93,7 @@ class SFTPFS(FS):
credentials
=
dict
(
username
=
username
,
password
=
password
,
pkey
=
pkey
)
self
.
credentials
=
credentials
if
encoding
is
None
:
encoding
=
"utf8"
...
...
@@ -103,7 +104,12 @@ class SFTPFS(FS):
self
.
_tlocal
=
thread_local
()
self
.
_transport
=
None
self
.
_client
=
None
self
.
hostname
=
None
if
isinstance
(
connection
,
basestring
):
self
.
hostname
=
connection
elif
isinstance
(
connection
,
tuple
):
self
.
hostname
=
'
%
s:
%
s'
%
connection
super
(
SFTPFS
,
self
)
.
__init__
()
self
.
root_path
=
abspath
(
normpath
(
root_path
))
...
...
@@ -124,19 +130,18 @@ class SFTPFS(FS):
connection
.
start_client
()
if
(
password
or
pkey
)
and
not
connection
.
is_authenticated
():
if
not
connection
.
is_authenticated
():
try
:
if
pkey
:
connection
.
auth_publickey
(
username
,
pkey
)
if
not
connection
.
is_authenticated
()
and
password
:
connection
.
auth_password
(
username
,
password
)
connection
.
auth_password
(
username
,
password
)
if
not
connection
.
is_authenticated
():
if
not
connection
.
is_authenticated
():
self
.
_agent_auth
(
connection
,
username
)
if
not
connection
.
is_authenticated
():
if
not
connection
.
is_authenticated
():
connection
.
close
()
raise
RemoteConnectionError
(
'no auth'
)
...
...
@@ -145,8 +150,10 @@ class SFTPFS(FS):
raise
RemoteConnectionError
(
'SSH exception (
%
s)'
%
str
(
e
),
details
=
e
)
self
.
_transport
=
connection
def
__unicode__
(
self
):
return
'<SFTPFS:
%
s>'
%
self
.
desc
(
'/'
)
@classmethod
def
_agent_auth
(
cls
,
transport
,
username
):
"""
...
...
@@ -213,6 +220,21 @@ class SFTPFS(FS):
raise
PathError
(
path
,
msg
=
"Path is outside root:
%(path)
s"
)
return
npath
def
getpathurl
(
self
,
path
,
allow_none
=
False
):
path
=
self
.
_normpath
(
path
)
if
self
.
hostname
is
None
:
if
allow_none
:
return
None
raise
NoPathURLError
(
path
=
path
)
username
=
self
.
credentials
.
get
(
'username'
,
''
)
or
''
password
=
self
.
credentials
.
get
(
'password'
,
''
)
or
''
credentials
=
(
'
%
s:
%
s'
%
(
username
,
password
))
.
rstrip
(
':'
)
if
credentials
:
url
=
'sftp://
%
s@
%
s
%
s'
%
(
credentials
,
self
.
hostname
.
rstrip
(
'/'
),
abspath
(
path
))
else
:
url
=
'sftp://
%
s
%
s'
%
(
self
.
hostname
.
rstrip
(
'/'
),
abspath
(
path
))
return
url
@convert_os_errors
def
open
(
self
,
path
,
mode
=
"rb"
,
bufsize
=-
1
):
npath
=
self
.
_normpath
(
path
)
...
...
@@ -234,8 +256,11 @@ class SFTPFS(FS):
def
desc
(
self
,
path
):
npath
=
self
.
_normpath
(
path
)
addr
,
port
=
self
.
_transport
.
getpeername
()
return
u'
%
s on sftp://
%
s:
%
i'
%
(
self
.
client
.
normalize
(
npath
),
addr
,
port
)
if
self
.
hostname
:
return
u'sftp://
%
s
%
s'
%
(
self
.
hostname
,
path
)
else
:
addr
,
port
=
self
.
_transport
.
getpeername
()
return
u'sftp://
%
s:
%
i
%
s'
%
(
addr
,
port
,
self
.
client
.
normalize
(
npath
))
@convert_os_errors
def
exists
(
self
,
path
):
...
...
@@ -282,10 +307,9 @@ class SFTPFS(FS):
if
dirs_only
or
files_only
:
attrs
=
self
.
client
.
listdir_attr
(
npath
)
attrs_map
=
dict
((
a
.
filename
,
a
)
for
a
in
attrs
)
paths
=
attrs_map
.
keys
()
paths
=
list
(
attrs_map
.
iterkeys
())
else
:
paths
=
self
.
client
.
listdir
(
npath
)
paths
=
self
.
client
.
listdir
(
npath
)
except
IOError
,
e
:
if
getattr
(
e
,
"errno"
,
None
)
==
2
:
if
self
.
isfile
(
path
):
...
...
@@ -294,24 +318,25 @@ class SFTPFS(FS):
elif
self
.
isfile
(
path
):
raise
ResourceInvalidError
(
path
,
msg
=
"Can't list directory contents of a file:
%(path)
s"
)
raise
if
attrs_map
:
if
dirs_only
:
filter_paths
=
[]
for
path
,
attr
in
attrs_map
.
iteritems
():
for
a
path
,
attr
in
attrs_map
.
iteritems
():
if
isdir
(
self
,
path
,
attr
.
__dict__
):
filter_paths
.
append
(
path
)
filter_paths
.
append
(
a
path
)
paths
=
filter_paths
elif
files_only
:
filter_paths
=
[]
for
path
,
attr
in
attrs_map
.
iteritems
():
if
isfile
(
self
,
path
,
attr
.
__dict__
):
filter_paths
.
append
(
path
)
paths
=
filter_paths
for
a
path
,
attr
in
attrs_map
.
iteritems
():
if
isfile
(
self
,
a
path
,
attr
.
__dict__
):
filter_paths
.
append
(
a
path
)
paths
=
filter_paths
for
(
i
,
p
)
in
enumerate
(
paths
):
if
not
isinstance
(
p
,
unicode
):
paths
[
i
]
=
p
.
decode
(
self
.
encoding
)
paths
[
i
]
=
p
.
decode
(
self
.
encoding
)
return
self
.
_listdir_helper
(
path
,
paths
,
wildcard
,
full
,
absolute
,
False
,
False
)
...
...
@@ -477,7 +502,7 @@ class SFTPFS(FS):
@classmethod
def
_extract_info
(
cls
,
stats
):
fromtimestamp
=
datetime
.
datetime
.
fromtimestamp
info
=
dict
((
k
,
v
)
for
k
,
v
in
stats
.
iteritems
()
if
k
in
cls
.
_info_vars
)
info
=
dict
((
k
,
v
)
for
k
,
v
in
stats
.
iteritems
()
if
k
in
cls
.
_info_vars
and
not
k
.
startswith
(
'_'
)
)
info
[
'size'
]
=
info
[
'st_size'
]
ct
=
info
.
get
(
'st_ctime'
)
if
ct
is
not
None
:
...
...
@@ -494,7 +519,7 @@ class SFTPFS(FS):
def
getinfo
(
self
,
path
):
npath
=
self
.
_normpath
(
path
)
stats
=
self
.
client
.
stat
(
npath
)
info
=
dict
((
k
,
getattr
(
stats
,
k
))
for
k
in
dir
(
stats
)
if
not
k
.
startswith
(
'_
_'
)
)
info
=
dict
((
k
,
getattr
(
stats
,
k
))
for
k
in
dir
(
stats
)
if
not
k
.
startswith
(
'_
'
)
)
info
[
'size'
]
=
info
[
'st_size'
]
ct
=
info
.
get
(
'st_ctime'
,
None
)
if
ct
is
not
None
:
...
...
fs/wrapfs/subfs.py
View file @
e69d8929
...
...
@@ -30,18 +30,16 @@ class SubFS(WrapFS):
return
abspath
(
normpath
(
path
))[
len
(
self
.
sub_dir
):]
def
__str__
(
self
):
return
"
%
s/
%
s"
%
(
self
.
wrapped_fs
,
self
.
sub_dir
.
lstrip
(
'/'
))
return
self
.
wrapped_fs
.
desc
(
self
.
sub_dir
)
def
__unicode__
(
self
):
return
u
"
%
s/
%
s"
%
(
self
.
wrapped_fs
,
self
.
sub_dir
.
lstrip
(
'/'
))
return
u
'<SubFS:
%
s!
%
s>'
%
(
self
.
wrapped_fs
,
self
.
sub_dir
)
def
__repr__
(
self
):
return
str
(
self
)
def
desc
(
self
,
path
):
#return self.wrapped_fs.desc(join(self.sub_dir, path))
desc
=
"
%
s!
%
s"
%
(
str
(
self
),
path
)
return
desc
return
'
%
s!
%
s'
%
(
self
.
wrapped_fs
.
desc
(
self
.
sub_dir
),
path
)
def
setcontents
(
self
,
path
,
data
,
chunk_size
=
64
*
1024
):
path
=
self
.
_encode
(
path
)
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment