1 #!/usr/bin/env python 2 3 """ 4 Directory output context. 5 6 Copyright (C) 2018, 2019 Paul Boddie <paul@boddie.org.uk> 7 8 This program is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free Software 10 Foundation; either version 3 of the License, or (at your option) any later 11 version. 12 13 This program is distributed in the hope that it will be useful, but WITHOUT 14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 details. 17 18 You should have received a copy of the GNU General Public License along with 19 this program. If not, see <http://www.gnu.org/licenses/>. 20 """ 21 22 from moinformat.output.common import Output 23 from moinformat.utils.directory import Directory 24 from os.path import extsep, join, sep 25 26 class DirectoryOutput(Output): 27 28 "A directory output context." 29 30 name = "directory" 31 32 def __init__(self, metadata): 33 34 "Initialise the context with the given 'metadata'." 35 36 if not metadata.has_key("output_filename"): 37 raise ValueError, metadata 38 39 Output.__init__(self, metadata) 40 self.dir = Directory(metadata.get("output_filename")) 41 self.dir.ensure() 42 43 # Support an encoding of the level separator for the filesystem. 44 # Where it is the same as the directory separator, documents are stored 45 # using nested directories, not as a flat list. 46 47 self.level_sep = metadata.get("output_separator", sep) 48 49 # Use any document index setting as the default for the index filename. 50 51 document_index = metadata.get("document_index", "index.html") 52 self.index_name = metadata.get("index_name", document_index) 53 self.root_pagename = metadata.get("root_pagename") 54 self.attachments_dir = metadata.get("attachments") 55 56 # Support a common attachments directory. 57 58 self.common_attachments = metadata.get("common_attachments") 59 60 def _get_attachments_dir(self, pagename): 61 62 "Return the attachments directory for 'pagename'." 63 64 if self.common_attachments: 65 return join(self.dir.filename, self.attachments_dir) 66 else: 67 return join(self.dir.filename, self.attachments_dir, pagename) 68 69 # Convenience methods. 70 71 def ensure(self, pagename): 72 73 "Ensure that the given 'pagename' exists." 74 75 if not pagename: 76 return None 77 78 self.dir.ensure(self.to_filename(pagename)) 79 80 def ensure_attachments(self, pagename): 81 82 "Ensure that attachment storage for the given 'pagename' exists." 83 84 if not pagename: 85 return None 86 87 self.dir.ensure(self._get_attachments_dir(pagename)) 88 89 def get_attachment_filename(self, pagename, filename): 90 91 """ 92 Return the full path of an attachment file for the given 'pagename' 93 having the given 'filename'. 94 """ 95 96 if not pagename: 97 return None 98 99 return self.dir.get_filename(join(self._get_attachments_dir(pagename), filename)) 100 101 def get_filename(self, filename): 102 103 """ 104 Return the full path of a file with the given 'filename' found within 105 the directory. The full path is an absolute path. 106 """ 107 108 return self.dir.get_filename(filename) 109 110 # Name translation methods. 111 112 def to_filename(self, pagename): 113 114 "Return the filename corresponding to 'pagename'." 115 116 # Encode hierarchical filenames. 117 118 if self.level_sep == sep: 119 120 # For the root page, use the top-level directory. 121 122 if pagename == self.root_pagename: 123 return "" 124 else: 125 return pagename 126 127 # Encode single-directory filenames. 128 129 else: 130 return self.level_sep.join(pagename.split("/")) 131 132 def to_pagename(self, filename): 133 134 "Return the pagename corresponding to 'filename'." 135 136 # Encode pagenames from hierarchical filenames. 137 138 if self.level_sep == sep: 139 return self.within(filename) 140 141 # Encode pagenames from single-directory filenames. 142 143 else: 144 return "/".join(filename.split(self.level_sep)) 145 146 # Serialisation methods. 147 148 def can_write(self): 149 150 "Return whether this context supports page writing." 151 152 return True 153 154 def writefile(self, text, filename, encoding=None): 155 156 """ 157 Write 'text' to the file having the given 'filename'. If the 158 optional 'encoding' is specified, override the general encoding. 159 """ 160 161 return self.writepath(text, self.dir.get_filename(filename), encoding) 162 163 def writepage(self, text, pagename, encoding=None): 164 165 """ 166 Write 'text' to the file having the given 'pagename' and optional 167 'encoding'. If 'parent' is specified and a true value, it indicates that 168 the page is a parent of other pages. 169 """ 170 171 filename = self.to_filename(pagename) 172 173 # For hierarchical storage, store the page inside a directory bearing 174 # its name. 175 176 if self.level_sep == sep: 177 178 # Make a directory for the page. 179 180 if not self.dir.exists(filename): 181 self.dir.makedirs(filename) 182 183 # Write to an index filename within any existing directory. 184 185 filename = join(filename, self.index_name) 186 187 self.writefile(text, filename, encoding) 188 189 output = DirectoryOutput 190 191 # vim: tabstop=4 expandtab shiftwidth=4