1 /*******************************************************************************
2 
3         copyright:      Copyright (c) 2007 Kris Bell. All rights reserved
4 
5         license:        BSD style: $(LICENSE)
6 
7         version:        Oct 2007: Initial version
8 
9         author:         Kris
10 
11 *******************************************************************************/
12 
13 module tango.io.vfs.LinkedFolder;
14 
15 private import tango.io.vfs.model.Vfs;
16 
17 private import tango.core.Exception;
18 
19 private import tango.io.vfs.VirtualFolder;
20 
21 /*******************************************************************************
22         
23         LinkedFolder is derived from VirtualFolder, and behaves exactly the 
24         same in all but one aspect: it treats mounted folders as an ordered 
25         list of alternatives to look for a file. This supports the notion of 
26         file 'overrides', whereby "customized" files can be inserted into a 
27         chain of alternatives.
28 
29         (overridden folders are not currently supported)
30 
31 *******************************************************************************/
32 
33 
34 class LinkedFolder : VirtualFolder
35 {
36         private Link* head;
37 
38         /***********************************************************************
39 
40                 Linked-list of folders
41 
42         ***********************************************************************/
43 
44         private struct Link
45         {
46                 Link*     next;
47                 VfsFolder folder;
48 
49                 static Link* opCall(VfsFolder folder)
50                 {
51                         auto p = new Link;
52                         p.folder = folder;
53                         return p;
54                 }
55         }
56 
57         /***********************************************************************
58 
59                 All folder must have a name. No '.' or '/' chars are 
60                 permitted
61 
62         ***********************************************************************/
63 
64         this (const(char)[] name)
65         {
66                 super (name);
67         }
68 
69         /***********************************************************************
70 
71                 Add a child folder. The child cannot 'overlap' with others
72                 in the tree of the same type. Circular references across a
73                 tree of virtual folders are detected and trapped.
74 
75                 We add the new child at the end of an ordered list, which
76                 we subsequently traverse when looking up a file
77 
78                 The second argument represents an optional name that the
79                 mount should be known as, instead of the name exposed by 
80                 the provided folder (it is not an alias).
81 
82         ***********************************************************************/
83 
84         override final VfsHost mount (VfsFolder folder, const(char)[] name=null)
85         {
86                 // traverse to the end of the list
87                 auto link = &head;
88                 while (*link)
89                         link = &(*link).next;
90 
91                 // hook up the new folder
92                 *link = Link (folder);
93 
94                 // and let superclass deal with it 
95                 return super.mount (folder, name);
96         }
97 
98         /***********************************************************************
99 
100                 TODO: unhook a child folder.
101 
102         ***********************************************************************/
103 
104         override final VfsHost dismount (VfsFolder folder)
105         {
106                 assert (0, "LinkedFolder.dismount not implemented");
107         }
108 
109         /***********************************************************************
110 
111                 Return a file representation of the given path. If the
112                 path-head does not refer to an immediate child folder, 
113                 and does not match a symbolic link, it is considered to
114                 be unknown.
115 
116                 We scan the set of mounted folders, in the order mounted,
117                 looking for a match. Where one is found, we test to see
118                 that it really exists before returning the reference
119 
120         ***********************************************************************/
121 
122         @property final override VfsFile file (const(char)[] path)
123         {
124                 auto link = head;
125                 while (link)
126                       {
127                       //Stdout.formatln ("looking in {}", link.folder.toString);
128                       try {
129                           auto file = link.folder.file (path);
130                           if (file.exists)
131                               return file;
132                           } catch (VfsException x) {}
133                       link = link.next;
134                       }
135                 super.error ("file '"~path.idup~"' not found");
136                 return null;
137         }
138 }
139 
140 
141 debug (LinkedFolder)
142 {
143 /*******************************************************************************
144 
145 *******************************************************************************/
146 
147 import tango.io.Stdout;
148 import tango.io.vfs.FileFolder;
149 
150 void main()
151 {
152         auto root = new LinkedFolder ("root");
153         auto sub  = new VirtualFolder ("sub");
154         sub.mount (new FileFolder (r"d:/d/import/temp"));
155         sub.map (sub.file(r"temp/subtree/test.txt"), "wumpus");
156 
157         root.mount (new FileFolder (r"d:/d/import/tango"))
158             .mount (new FileFolder (r"c:/"), "windows");
159         root.mount (sub);
160 
161         auto file = root.file (r"wumpus");
162         Stdout.formatln ("file = {}", file);
163 }
164 }