|
1 # Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. |
|
2 # This component and the accompanying materials are made available under the terms of the License |
|
3 # "Eclipse Public License v1.0" which accompanies this distribution, |
|
4 # and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
5 # |
|
6 # Initial Contributors: |
|
7 # Nokia Corporation - initial contribution. |
|
8 # |
|
9 # Contributors: |
|
10 # System Documentation Tools |
|
11 # Description: |
|
12 # |
|
13 import os.path |
|
14 import sys |
|
15 import unittest |
|
16 import xml |
|
17 import stat |
|
18 import logging |
|
19 from cStringIO import StringIO |
|
20 from xml.etree import ElementTree as etree |
|
21 from lib import scan, main, XmlParser, StubXmlParser |
|
22 from optparse import OptionParser |
|
23 |
|
24 __version__ = '0.1' |
|
25 |
|
26 |
|
27 UNSAFE_CHARS = ("\n", "\t", ":", "?", ",", "=", ".", "\\", "/", "[", "]", "|", "<", ">", "+", ";", '"', "-") |
|
28 |
|
29 |
|
30 class FileRenamer(object): |
|
31 """ |
|
32 Given an xml file this class returns a MODE compatable filename |
|
33 |
|
34 >>> fr = FileRenamer(xmlparser=StubXmlParser()) |
|
35 >>> fr.rename(r"c:\\temp\\xml\\class_c_active_scheduler.xml") |
|
36 'class_c_active_scheduler=GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F=1=en=.reference' |
|
37 """ |
|
38 def __init__(self, xmlparser=XmlParser(), publishing_target="mode"): |
|
39 self.parser = xmlparser |
|
40 self.publishing_target = publishing_target |
|
41 |
|
42 def _escape(self, filename): |
|
43 for char in UNSAFE_CHARS: |
|
44 filename = filename.replace(char, "") |
|
45 filename = filename.encode('unicode-escape', 'ignore') |
|
46 filename = filename.replace(" ", "-") |
|
47 return filename |
|
48 |
|
49 def rename(self, xmlfile): |
|
50 """ |
|
51 Return DITA MODE compliant filename. |
|
52 Format of resultant filenames is: |
|
53 title=identifier=version=language=resolution.extension |
|
54 Examples: |
|
55 Test-Document=GUID-1234=1=en=.reference |
|
56 """ |
|
57 id = self.parser.parse(xmlfile) |
|
58 filename = os.path.basename(xmlfile) |
|
59 filename, ext = os.path.splitext(filename) |
|
60 if self.publishing_target == "mode": |
|
61 filename = self._escape(filename) |
|
62 newfilename = "=".join((filename, id, '1', 'en', '')) |
|
63 ext = ext if ext == ".ditamap" else ".reference" |
|
64 elif self.publishing_target == "ditaot": |
|
65 newfilename = id |
|
66 ext = ext = ext if ext == ".ditamap" else ".xml" |
|
67 return newfilename + ext |
|
68 |
|
69 |
|
70 def rename(indir, publishing_target): |
|
71 fr = FileRenamer(publishing_target=publishing_target) |
|
72 for filepath in scan(indir): |
|
73 newfilename = os.path.join(os.path.dirname(filepath), fr.rename(filepath)) |
|
74 try: |
|
75 os.chmod(filepath, stat.S_IWRITE) |
|
76 except Exception, e: |
|
77 logging.error('Unable to make file \"%s\" writable, error was: %s' % (filepath, e)) |
|
78 continue |
|
79 else: |
|
80 logging.debug("Renaming %s to %s" % (filepath, newfilename)) |
|
81 try: |
|
82 os.rename(filepath, newfilename) |
|
83 except Exception, e: |
|
84 logging.error('Unable to rename file \"%s\" to \"%s\", error was: %s' % (filepath, newfilename, e)) |
|
85 |
|
86 def main(): |
|
87 usage = "usage: %prog <Path to the XML content> <publishing_target>\n" |
|
88 parser = OptionParser(usage, version='%prog ' + __version__) |
|
89 parser.add_option("-p", dest="publishing_target", type="choice", choices=["mode", "ditaot"], default="mode", |
|
90 help="Publishing Target: mode|ditaot, [default: %default]") |
|
91 parser.add_option("-l", "--loglevel", type="int", default=30, help="Log Level (debug=10, info=20, warning=30, [error=40], critical=50)") |
|
92 (options, args) = parser.parse_args() |
|
93 if len(args) < 1: |
|
94 parser.print_help() |
|
95 parser.error("Please supply the path to the XML content") |
|
96 |
|
97 if options.loglevel: |
|
98 logging.basicConfig(level=options.loglevel) |
|
99 |
|
100 rename(args[0],options.publishing_target) |
|
101 |
|
102 if __name__ == '__main__': |
|
103 sys.exit(main()) |
|
104 |
|
105 ###################################### |
|
106 # Test code |
|
107 ###################################### |
|
108 |
|
109 class TestFileRenamer(unittest.TestCase): |
|
110 def test_i_can_return_a_files_new_mode_name(self): |
|
111 fr = FileRenamer(xmlparser=StubXmlParser(),publishing_target="mode") |
|
112 newfile = fr.rename("hello.xml") |
|
113 self.assertTrue(newfile == "hello=GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F=1=en=.reference") |
|
114 |
|
115 def test_i_can_return_a_ditamaps_new_mode_name(self,publishing_target="mode"): |
|
116 fr = FileRenamer(xmlparser=StubXmlParser()) |
|
117 newfile = fr.rename("hello.ditamap") |
|
118 self.assertTrue(newfile == "hello=GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F=1=en=.ditamap") |
|
119 |
|
120 |
|
121 def test_i_can_return_a_files_new_name_if_passed_an_absolute_path(self): |
|
122 fr = FileRenamer(xmlparser=StubXmlParser()) |
|
123 newfile = fr.rename("c:\\temp\\xml\\hello.xml") |
|
124 self.assertTrue(newfile == "hello=GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F=1=en=.reference") |
|
125 |
|
126 def test_i_can_remove_incompatable_characters_from_a_filename(self): |
|
127 fr = FileRenamer(xmlparser=StubXmlParser()) |
|
128 newfile = fr.rename("hello:?,=..xml") |
|
129 self.assertTrue(newfile , "hello=GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F=1=en=.reference") |
|
130 |
|
131 def test_i_can_return_a_files_new_ditaot_name(self): |
|
132 fr = FileRenamer(xmlparser=StubXmlParser(),publishing_target="ditaot") |
|
133 newfile = fr.rename("hello.xml") |
|
134 self.assertEquals(newfile, "GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F.xml") |
|
135 |
|
136 def test_i_can_return_a_ditamaps_new_ditaot_name(self): |
|
137 fr = FileRenamer(xmlparser=StubXmlParser(),publishing_target="ditaot") |
|
138 newfile = fr.rename("hello.ditamap") |
|
139 self.assertEquals(newfile, "GUID-BED8A733-2ED7-31AD-A911-C1F4707C67F.ditamap") |