├── .gitignore ├── CONTRIBUTORS.txt ├── HISTORY.txt ├── INSTALL ├── LICENSE ├── MANIFEST.in ├── README.md ├── clonedigger ├── LICENSE.txt ├── README.txt ├── __init__.py ├── abstract_syntax_tree.py ├── anti_unification.py ├── antlr_runtime │ ├── antlr-3.1.1.jar │ ├── antlr-runtime-3.1.jar │ └── runtime-2008-01-10.16.jar ├── arguments.py ├── ast_suppliers.py ├── clone_detection_algorithm.py ├── clonedigger.py ├── html_report.py ├── java_antlr.py ├── java_antlr │ ├── JavaAST.g │ ├── JavaAST.tokens │ ├── MyAstNode.java │ ├── MyAstNodeAdaptor.java │ ├── TreeProducer.jar │ ├── TreeProducer.java │ └── build_jar.sh ├── js_antlr.py ├── js_antlr │ ├── JavaScript.g │ ├── JavaScript.tokens │ ├── JavaScriptLexer.java │ ├── JavaScriptParser.java │ ├── MyAstNode.java │ ├── MyAstNodeAdaptor.java │ ├── TreeProducer.jar │ ├── TreeProducer.java │ ├── build_jar.sh │ └── license.txt ├── logilab │ ├── __init__.py │ ├── astng │ │ ├── __init__.py │ │ ├── __pkginfo__.py │ │ ├── _exceptions.py │ │ ├── astutils.py │ │ ├── builder.py │ │ ├── inference.py │ │ ├── inspector.py │ │ ├── lookup.py │ │ ├── manager.py │ │ ├── nodes.py │ │ ├── raw_building.py │ │ ├── scoped_nodes.py │ │ └── utils.py │ └── common │ │ ├── __init__.py │ │ ├── __pkginfo__.py │ │ ├── adbh.py │ │ ├── astutils.py │ │ ├── bind.py │ │ ├── cache.py │ │ ├── changelog.py │ │ ├── clcommands.py │ │ ├── cli.py │ │ ├── compat.py │ │ ├── configuration.py │ │ ├── corbautils.py │ │ ├── daemon.py │ │ ├── date.py │ │ ├── db.py │ │ ├── debugger.py │ │ ├── decorators.py │ │ ├── deprecation.py │ │ ├── fileutils.py │ │ ├── graph.py │ │ ├── html.py │ │ ├── interface.py │ │ ├── logger.py │ │ ├── logging_ext.py │ │ ├── logservice.py │ │ ├── modutils.py │ │ ├── monclient.py │ │ ├── monserver.py │ │ ├── optik_ext.py │ │ ├── optparser.py │ │ ├── patricia.py │ │ ├── pdf_ext.py │ │ ├── pytest.py │ │ ├── shellutils.py │ │ ├── sqlgen.py │ │ ├── table.py │ │ ├── testlib.py │ │ ├── textutils.py │ │ ├── tree.py │ │ ├── twisted_distutils.py │ │ ├── umessage.py │ │ ├── ureports │ │ ├── __init__.py │ │ ├── docbook_writer.py │ │ ├── html_writer.py │ │ ├── nodes.py │ │ └── text_writer.py │ │ ├── vcgutils.py │ │ ├── visitor.py │ │ └── xmlrpcutils.py ├── lua_antlr.py ├── lua_antlr │ ├── Lua.g │ ├── TreeProducer.jar │ ├── TreeProducer.java │ └── build_jar.sh ├── python_compiler.py └── suffix_tree.py ├── eclipse_plugin_manual ├── Run.gif ├── RunDone.gif ├── RunFirst.gif ├── RunInstall.gif ├── RunPopup.gif ├── SUpdate.gif ├── SUpdateAdd.gif ├── SUpdateInstall.gif ├── Update.gif └── eclipse_plugin_manual.html ├── ez_setup.py ├── org.clonedigger.feature ├── artifacts.xml ├── build.properties ├── content.xml ├── feature.xml ├── features │ ├── org.clonedigger.feature_1.1.3.jar │ ├── org.clonedigger.feature_1.1.4.jar │ ├── org.clonedigger.feature_1.1.5.jar │ ├── org.clonedigger.feature_1.1.6.jar │ ├── org.clonedigger.feature_1.1.7.jar │ └── org.clonedigger.feature_1.1.8.jar ├── plugins │ ├── org.clonedigger_1.1.3.jar │ ├── org.clonedigger_1.1.4.jar │ ├── org.clonedigger_1.1.5.jar │ ├── org.clonedigger_1.1.6.jar │ ├── org.clonedigger_1.1.7.jar │ └── org.clonedigger_1.1.8.jar └── site.xml ├── org.clonedigger ├── .classpath ├── .settings │ ├── org.eclipse.core.resources.prefs │ └── org.eclipse.jdt.core.prefs ├── META-INF │ └── MANIFEST.MF ├── build.properties ├── ez_setup.py ├── icons │ └── icon.gif ├── plugin.xml ├── runclonedigger.py ├── setup.py └── src │ └── org │ └── clonedigger │ ├── Activator.java │ ├── ResultBrowser.java │ └── actions │ ├── DigAction.java │ └── UpdateAction.java ├── release.sh └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | __pycache__ 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | -------------------------------------------------------------------------------- /CONTRIBUTORS.txt: -------------------------------------------------------------------------------- 1 | This software was originaly written by Peter Bulychev (http://clonedigger.sourceforge.net/authors.html) 2 | 3 | -------------------------------------------------------------------------------- /HISTORY.txt: -------------------------------------------------------------------------------- 1 | History 2 | ======= 3 | 4 | 2014/01/31: 5 | ----------- 6 | MANIFEST.in file update, include: 7 | - .g 8 | - .jar 9 | - .java 10 | - .tokens 11 | - .sh 12 | 13 | 2014/01/27: 14 | ----------- 15 | Initial clone of http://sourceforge.net/projects/clonedigger/ to github repository 16 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Use "setup.py install" to install Clone Digger. 2 | 3 | You might get "NameError: global name 'log' is not defined". It is a bug caused by distutils. You should remove .svn directory to overpass it. 4 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include HISTORY.txt 2 | include CONTRIBUTORS.txt 3 | include README.md 4 | include LICENSE 5 | include ez_setup.py 6 | recursive-include clonedigger *.py *.txt *.g *.jar *.java *.tokens *.sh 7 | 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | clonedigger 2 | =========== 3 | 4 | This is a clone of the Python duplicate code detection tool 5 | from http://sourceforge.net/projects/clonedigger/ by Peter Bulychev 6 | -------------------------------------------------------------------------------- /clonedigger/README.txt: -------------------------------------------------------------------------------- 1 | =================== 2 | Clone Digger README 3 | =================== 4 | 5 | available at http://clonedigger.sourceforge.net 6 | 7 | Clone Digger is the tool for finding software clones. 8 | Currently only Python language is supported, Java support will be added soon. 9 | See the site for details. 10 | 11 | Usage 12 | ===== 13 | 14 | The simplest way of running Clone Digger is:: 15 | 16 | clonedigger source_file_1 source_file_2 ... 17 | 18 | Or:: 19 | 20 | clonedigger --recursive path_to_source_tree 21 | 22 | Don't forget to remove automatically generated sources, tests and third party libraries from the source tree. 23 | 24 | See http://clonedigger.sourceforge.net/documentation.html for more complex arguments. 25 | 26 | The available arguments can be obtained using '--help' also. 27 | -------------------------------------------------------------------------------- /clonedigger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/__init__.py -------------------------------------------------------------------------------- /clonedigger/anti_unification.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import unicode_literals 3 | from __future__ import print_function 4 | from __future__ import division 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import range 8 | from builtins import * 9 | from builtins import object 10 | # Copyright 2008 Peter Bulychev 11 | # 12 | # This file is part of Clone Digger. 13 | # 14 | # Clone Digger is free software: you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation, either version 3 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # Clone Digger is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with Clone Digger. If not, see . 26 | 27 | import copy 28 | import sys 29 | 30 | from .abstract_syntax_tree import * 31 | from . import suffix_tree 32 | from . import arguments 33 | 34 | # NOTE that everywhere is written Unifier instead of AntiUnifier, for simplicity 35 | 36 | # Constants here 37 | verbose = True 38 | 39 | class FreeVariable(AbstractSyntaxTree): 40 | free_variables_count = 1 41 | def __init__(self): 42 | global free_variables_count 43 | FreeVariable.free_variables_count += 1 44 | name = 'VAR(%d)'%(FreeVariable.free_variables_count, ) 45 | # self._childs = [] 46 | AbstractSyntaxTree.__init__(self, name) 47 | 48 | class Substitution(object): 49 | def __init__(self, initial_value = None): 50 | if initial_value == None: 51 | initial_value = {} 52 | self._map = initial_value 53 | def substitute(self, tree, without_copying=False): 54 | if tree in list(self._map.keys()): 55 | return self._map[tree] 56 | else: 57 | if isinstance(tree, FreeVariable): 58 | return tree 59 | if without_copying: 60 | return tree 61 | else: 62 | r = AbstractSyntaxTree(tree.getName()) 63 | for child in tree.getChilds(): 64 | r.addChild(self.substitute(child, without_copying)) 65 | return r 66 | 67 | def getMap(self): 68 | return self._map 69 | def getSize(self): 70 | ret = 0 71 | for (u, tree) in list(self.getMap().items()): 72 | ret += tree.getSize(False) - free_variable_cost 73 | return ret 74 | 75 | class Unifier(object): 76 | def __init__(self, t1, t2, ignore_parametrization=False): 77 | def combineSubs(node, s, t): 78 | # s and t are 2-tuples 79 | assert(list(s[0].getMap().keys()) == list(s[1].getMap().keys())) 80 | assert(list(t[0].getMap().keys()) == list(t[1].getMap().keys())) 81 | newt = (copy.copy(t[0]), copy.copy(t[1])) 82 | relabel = {} 83 | for si in list(s[0].getMap().keys()): 84 | if not ignore_parametrization: 85 | foundone = False 86 | for ti in list(t[0].getMap().keys()): 87 | if (s[0].getMap()[si] == t[0].getMap()[ti]) and (s[1].getMap()[si] == t[1].getMap()[ti]): 88 | relabel[si] = ti 89 | foundone = True 90 | break 91 | if ignore_parametrization or not foundone: 92 | newt[0].getMap()[si] = s[0].getMap()[si] 93 | newt[1].getMap()[si] = s[1].getMap()[si] 94 | return (Substitution(relabel).substitute(node), newt) 95 | def unify(node1, node2): 96 | if node1 == node2: 97 | return (node1, (Substitution(), Substitution())) 98 | elif (node1.getName() != node2.getName()) or (node1.getChildCount() != node2.getChildCount()): 99 | var = FreeVariable() 100 | return (var, (Substitution({var:node1}), Substitution({var:node2}))) 101 | else: 102 | s = (Substitution(), Substitution()) 103 | name = node1.getName() 104 | retNode = AbstractSyntaxTree(name) 105 | count = node1.getChildCount() 106 | for i in range(count): 107 | (ai, si) = unify(node1.getChilds()[i], node2.getChilds()[i]) 108 | (ai, s) = combineSubs(ai, si, s) 109 | retNode.addChild(ai) 110 | return (retNode, s) 111 | (self._unifier, self._substitutions) = unify(t1, t2) 112 | self._unifier.storeSize() 113 | for i in (0,1): 114 | for key in self._substitutions[i].getMap(): 115 | self._substitutions[i].getMap()[key].storeSize() 116 | def getSubstitutions(self): 117 | return self._substitutions 118 | def getUnifier(self): 119 | return self._unifier 120 | def getSize(self): 121 | return sum([s.getSize() for s in self.getSubstitutions()]) 122 | 123 | class Cluster(object): 124 | count = 0 125 | def __init__(self, tree=None): 126 | if tree: 127 | self._n = 1 128 | self._unifier_tree = tree 129 | self._trees = [tree] 130 | self._max_covered_lines = len(tree.getCoveredLineNumbers()) 131 | else: 132 | self._n = 0 133 | self._trees = [] 134 | self._max_covered_lines = 0 135 | Cluster.count += 1 136 | self._cluster_number = Cluster.count 137 | def getUnifierTree(self): 138 | return self._unifier_tree 139 | def getCount(self): 140 | return self._n 141 | def getAddCost(self, tree): 142 | unifier = Unifier(self.getUnifierTree(), tree) 143 | return (self.getCount()* unifier.getSubstitutions()[0].getSize() + unifier.getSubstitutions()[1].getSize()) 144 | def unify(self, tree): 145 | self._n += 1 146 | self._unifier_tree = Unifier(self.getUnifierTree(), tree).getUnifier() 147 | self._trees.append(tree) 148 | def eraseAllTrees(self): 149 | self._n = 0 150 | self._trees = [] 151 | def addWithoutUnification(self, tree): 152 | self._n += 1 153 | self._trees.append(tree) 154 | if len(tree.getCoveredLineNumbers())>self._max_covered_lines: 155 | self._max_covered_lines = len(tree.getCoveredLineNumbers()) 156 | def getMaxCoveredLines(self): 157 | return self._max_covered_lines 158 | def getUnifierSize(self): 159 | return self.getUnifierTree().getSize() 160 | -------------------------------------------------------------------------------- /clonedigger/antlr_runtime/antlr-3.1.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/antlr_runtime/antlr-3.1.1.jar -------------------------------------------------------------------------------- /clonedigger/antlr_runtime/antlr-runtime-3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/antlr_runtime/antlr-runtime-3.1.jar -------------------------------------------------------------------------------- /clonedigger/antlr_runtime/runtime-2008-01-10.16.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/antlr_runtime/runtime-2008-01-10.16.jar -------------------------------------------------------------------------------- /clonedigger/arguments.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from __future__ import print_function 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | clustering_threshold = 10 9 | hashing_depth = 1 10 | clusterize_using_dcup = False 11 | report_unifiers = False 12 | print_time = True 13 | force = False 14 | use_diff = False 15 | clusterize_using_hash = False 16 | -------------------------------------------------------------------------------- /clonedigger/ast_suppliers.py: -------------------------------------------------------------------------------- 1 | from __future__ import absolute_import 2 | from __future__ import unicode_literals 3 | from __future__ import print_function 4 | from __future__ import division 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | # Copyright 2008 Peter Bulychev 9 | # http://clonedigger.sourceforge.net 10 | # 11 | # This file is part of Clone Digger. 12 | # 13 | # Clone Digger is free software: you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation, either version 3 of the License, or 16 | # (at your option) any later version. 17 | # 18 | # Clone Digger is distributed in the hope that it will be useful, 19 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | # GNU General Public License for more details. 22 | # 23 | # You should have received a copy of the GNU General Public License 24 | # along with Clone Digger. If not, see . 25 | 26 | # Abstract Syntax Tree suppliers 27 | abstract_syntax_tree_suppliers = {} 28 | 29 | from . import python_compiler 30 | abstract_syntax_tree_suppliers['python'] = python_compiler.PythonCompilerSourceFile 31 | 32 | from . import java_antlr 33 | abstract_syntax_tree_suppliers['java'] = java_antlr.JavaANTLRSourceFile 34 | 35 | from . import lua_antlr 36 | abstract_syntax_tree_suppliers['lua'] = lua_antlr.LuaANTLRSourceFile 37 | 38 | from . import js_antlr 39 | abstract_syntax_tree_suppliers['javascript'] = js_antlr.JsANTLRSourceFile 40 | abstract_syntax_tree_suppliers['js'] = js_antlr.JsANTLRSourceFile 41 | -------------------------------------------------------------------------------- /clonedigger/java_antlr.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from __future__ import absolute_import 3 | from __future__ import unicode_literals 4 | from __future__ import division 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | from builtins import object 9 | # Copyright 2008 Peter Bulychev 10 | # http://clonedigger.sourceforge.net 11 | # 12 | # This file is part of Clone Digger. 13 | # 14 | # Clone Digger is free software: you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation, either version 3 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # Clone Digger is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with Clone Digger. If not, see . 26 | 27 | import os 28 | import xml.parsers.expat 29 | 30 | from .abstract_syntax_tree import * 31 | 32 | 33 | class JavaANTLRSourceFile (SourceFile): 34 | extension = 'java' 35 | size_threshold = 10 36 | distance_threshold = 7 37 | 38 | def __init__(self, file_name): 39 | SourceFile.__init__(self, file_name) 40 | 41 | class ExpatHandler(object): 42 | def __init__(self, start_node, parent): 43 | self.parent = parent 44 | self.stack = [start_node] 45 | 46 | def start_element(expat_self, xml_node_name, attrs): 47 | line_number = int(attrs["line_number"]) - 1 48 | line_numbers = [line_number] 49 | if line_numbers == [-1]: 50 | line_numbers = [] 51 | name = attrs["name"] 52 | r = AbstractSyntaxTree(name, line_numbers, self) 53 | if xml_node_name == "statement_node": 54 | r.markAsStatement() 55 | else: 56 | assert(xml_node_name == "node") 57 | expat_self.stack[-1].addChild(r) 58 | expat_self.stack.append(r) 59 | 60 | def end_element(self, name): 61 | self.stack.pop() 62 | 63 | tree_file_name = 'temporary_ast.xml' 64 | current_directory = os.path.realpath(os.path.dirname(__file__)) 65 | producer_class_path = os.path.join( 66 | current_directory, 'java_antlr', 'TreeProducer.jar') 67 | antlr_class_path = os.path.join( 68 | current_directory, 'antlr_runtime', 'runtime-2008-01-10.16.jar') 69 | if os.name in ['mac', 'posix']: 70 | class_path_delimeter = ':' 71 | elif os.name in ['nt', 'dos', 'ce']: 72 | class_path_delimeter = ';' 73 | else: 74 | print('unsupported OS') 75 | assert(0) 76 | command = ( 77 | 'java -classpath ' + producer_class_path 78 | + class_path_delimeter + antlr_class_path 79 | + ' TreeProducer %s %s 2>err.log' % (file_name, tree_file_name)) 80 | if os.system(command): 81 | f = open('err.log') 82 | s = f.read() 83 | f.close() 84 | raise Exception(s) 85 | 86 | self._tree = AbstractSyntaxTree('program') 87 | handler = ExpatHandler(self._tree, self) 88 | p = xml.parsers.expat.ParserCreate() 89 | p.StartElementHandler = handler.start_element 90 | p.EndElementHandler = handler.end_element 91 | f = open(tree_file_name) 92 | p.ParseFile(f) 93 | f.close() 94 | os.remove(tree_file_name) 95 | -------------------------------------------------------------------------------- /clonedigger/java_antlr/JavaAST.tokens: -------------------------------------------------------------------------------- 1 | T__197=197 2 | FORMAL_PARAMETERS=39 3 | T__139=139 4 | PACKAGE_DECLARATION=5 5 | T__174=174 6 | HexDigit=101 7 | TYPE_ARGUMENTS=37 8 | T__196=196 9 | T__144=144 10 | T__122=122 11 | T__115=115 12 | ANNOTATION_INTERFACE=50 13 | T__137=137 14 | SIGNED_RIGHT_SHIFT=72 15 | UNSIGNED_RIGHT_SHIFT_ASSIGN=66 16 | T__140=140 17 | ENHANCED_FOR_CONTROL=62 18 | Letter=108 19 | COMPILATION_UNIT=4 20 | INTERFACE_DECLARATION=20 21 | LEFT_SHIFT=70 22 | CLASS_DESIGNATOR=79 23 | TYPE_BOUND=14 24 | CLASS_BODY=21 25 | T__138=138 26 | SELECT=36 27 | CONSTRUCTOR_DECLARATION=29 28 | T__173=173 29 | T__119=119 30 | CLASS_DECLARATION=11 31 | ASSERT=99 32 | MARKER_ANNOTATION=47 33 | EXPRESSION_STATEMENT=57 34 | T__198=198 35 | T__142=142 36 | T__176=176 37 | FloatTypeSuffix=104 38 | T__118=118 39 | T__135=135 40 | T__113=113 41 | ENUM_BODY=16 42 | FORMAL_PARAMETER=40 43 | IntegerTypeSuffix=102 44 | ARGUMENTS=91 45 | T__156=156 46 | NEW_ARRAY=87 47 | WS=110 48 | T__159=159 49 | T__177=177 50 | UNQUALIFIED_SUPER=78 51 | T__158=158 52 | NON_WILD_TYPE_ARGUMENTS=89 53 | LOCAL_VARIABLE_DECLARATION=54 54 | UnicodeEscape=106 55 | T__157=157 56 | ENUM_DECLARATION=15 57 | T__201=201 58 | T__114=114 59 | SINGLE_ELEMENT_ANNOTATION=46 60 | MODIFIERS=10 61 | T__143=143 62 | UNQUALIFIED_CLASS_INSTANCE_CREATION=84 63 | T__193=193 64 | T__141=141 65 | EMPTY_STATEMENT=56 66 | ENUM_BODY_DECLARATIONS=19 67 | OctalLiteral=97 68 | T__167=167 69 | T__194=194 70 | CAST=76 71 | EXPRESSION_LIST=64 72 | T__191=191 73 | TYPE_IMPORT_ON_DEMAND_DECLARATION=7 74 | SWITCH_BLOCK_STATEMENT_GROUP=58 75 | BLOCK=53 76 | UNSIGNED_RIGHT_SHIFT=71 77 | T__192=192 78 | EscapeSequence=105 79 | INTERFACE_BODY=22 80 | NEW_INITIALIZED_ARRAY=86 81 | SINGLE_STATIC_IMPORT_DECLARATION=8 82 | TYPE_PARAMETERS=12 83 | ELEMENT_VALUE_PAIR=48 84 | FloatingPointLiteral=93 85 | T__175=175 86 | ARRAY_OF=32 87 | T__117=117 88 | CONSTRUCTOR_BODY=34 89 | COMMENT=111 90 | T__199=199 91 | T__172=172 92 | STATIC_IMPORT_ON_DEMAND_DECLARATION=9 93 | THIS=77 94 | JavaIDDigit=109 95 | T__170=170 96 | T__136=136 97 | NORMAL_ANNOTATION=45 98 | T__116=116 99 | T__171=171 100 | CALL=81 101 | T__189=189 102 | OctalEscape=107 103 | T__134=134 104 | T__195=195 105 | PREFIX_EXPRESSION=73 106 | FOR_INIT_DECLARATION=60 107 | T__162=162 108 | FOR_INIT_EXPRESSION_LIST=61 109 | FIELD_DECLARATION=26 110 | INSTANTIATION=35 111 | T__160=160 112 | T__123=123 113 | T__145=145 114 | POST_INCREMENT_EXPRESSION=74 115 | T__187=187 116 | GREATER_THAN_OR_EQUAL_TO=69 117 | CONSTANT_DECLARATION=31 118 | T__186=186 119 | ELEMENT_VALUE_ARRAY_INITIALIZER=49 120 | T__181=181 121 | SINGLE_TYPE_IMPORT_DECLARATION=6 122 | T__128=128 123 | STATIC_INITIALIZER=23 124 | BASIC_FOR_CONTROL=59 125 | ENUM_CONSTANTS=17 126 | LAST_FORMAL_PARAMETER=41 127 | T__161=161 128 | T__168=168 129 | T__150=150 130 | Identifier=100 131 | QUALIFIED_THIS=82 132 | ENUM_CONSTANT=18 133 | ANNOTATION_METHOD=52 134 | T__182=182 135 | T__165=165 136 | T__130=130 137 | T__151=151 138 | LINE_COMMENT=112 139 | QUALIFIED_SUPERCLASS_CONSTRUCTOR_INVOCATION=44 140 | METHOD_DECLARATION=27 141 | HexLiteral=96 142 | T__125=125 143 | T__149=149 144 | T__166=166 145 | DecimalLiteral=98 146 | T__132=132 147 | ARRAY_INITIALIZER=33 148 | INNER_THIS=90 149 | LESS_THAN_OR_EQUAL_TO=68 150 | POST_DECREMENT_EXPRESSION=75 151 | T__190=190 152 | T__124=124 153 | T__131=131 154 | T__169=169 155 | QUALIFIED_SUPER=83 156 | ALTERNATE_CONSTRUCTOR_INVOCATION=42 157 | T__126=126 158 | T__148=148 159 | INSTANCE_INITIALIZER=24 160 | UNQUALIFIED_SUPERCLASS_CONSTRUCTOR_INVOCATION=43 161 | T__188=188 162 | T__200=200 163 | TYPE_PARAMETER=13 164 | T__127=127 165 | VOID=25 166 | T__183=183 167 | T__133=133 168 | ARRAY_ACCESS=80 169 | T__164=164 170 | T__120=120 171 | ENUM=92 172 | T__163=163 173 | Exponent=103 174 | T__153=153 175 | SIGNED_RIGHT_SHIFT_ASSIGN=67 176 | T__185=185 177 | CharacterLiteral=94 178 | T__178=178 179 | WILDCARD=38 180 | LEFT_SHIFT_ASSIGN=65 181 | StringLiteral=95 182 | T__129=129 183 | T__180=180 184 | EXPLICIT_GENERIC_INVOCATIONS=88 185 | T__152=152 186 | VARIABLE_DECLARATOR=30 187 | ANNOTATION_TYPE_BODY=51 188 | T__121=121 189 | QUALIFIED_CLASS_INSTANCE_CREATION=85 190 | FOR_UPDATE=63 191 | ASSERT_STATEMENT=55 192 | T__147=147 193 | T__179=179 194 | T__154=154 195 | ABSTRACT_METHOD_DECLARATION=28 196 | T__184=184 197 | T__155=155 198 | T__146=146 199 | '<'=128 200 | '-='=179 201 | 'interface'=134 202 | '>'=130 203 | 'case'=177 204 | 'try'=169 205 | 'boolean'=144 206 | 'else'=165 207 | '/='=181 208 | 'package'=113 209 | '-'=194 210 | '?'=152 211 | '!='=191 212 | '%='=185 213 | 'do'=168 214 | '||'=186 215 | 'double'=151 216 | '='=139 217 | '*='=180 218 | 'volatile'=143 219 | 'instanceof'=192 220 | 'super'=153 221 | 'strictfp'=124 222 | '|='=183 223 | 'native'=140 224 | '++'=197 225 | '{'=132 226 | 'void'=135 227 | 'catch'=176 228 | 'throws'=138 229 | 'float'=150 230 | 'new'=201 231 | ':'=163 232 | 'for'=166 233 | '.'=117 234 | '*'=118 235 | 'short'=147 236 | '}'=133 237 | '~'=199 238 | 'finally'=170 239 | 'break'=174 240 | '%'=196 241 | 'final'=123 242 | ';'=114 243 | 'synchronized'=141 244 | 'default'=162 245 | ']'=137 246 | 'true'=159 247 | 'false'=160 248 | '&'=131 249 | ','=129 250 | '&&'=187 251 | 'int'=148 252 | '&='=182 253 | 'while'=167 254 | 'this'=157 255 | 'continue'=175 256 | '['=136 257 | '/'=195 258 | '^'=189 259 | 'long'=149 260 | 'private'=121 261 | '|'=188 262 | 'return'=172 263 | ')'=155 264 | '=='=190 265 | 'static'=116 266 | 'implements'=127 267 | '@'=161 268 | 'throw'=173 269 | 'protected'=120 270 | 'import'=115 271 | '!'=200 272 | 'if'=164 273 | 'char'=145 274 | '+='=178 275 | 'switch'=171 276 | '('=154 277 | 'transient'=142 278 | 'byte'=146 279 | 'extends'=126 280 | '--'=198 281 | '^='=184 282 | 'class'=125 283 | '+'=193 284 | 'null'=158 285 | '...'=156 286 | 'public'=119 287 | 'abstract'=122 288 | -------------------------------------------------------------------------------- /clonedigger/java_antlr/MyAstNode.java: -------------------------------------------------------------------------------- 1 | import org.antlr.runtime.tree.*; 2 | import org.antlr.runtime.Token; 3 | 4 | import java.io.*; 5 | 6 | public class MyAstNode extends CommonTree { 7 | boolean is_statement = false; 8 | public MyAstNode(Token t) { 9 | super(t); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /clonedigger/java_antlr/MyAstNodeAdaptor.java: -------------------------------------------------------------------------------- 1 | import org.antlr.runtime.tree.*; 2 | import org.antlr.runtime.Token; 3 | 4 | class MyAstNodeAdaptor extends CommonTreeAdaptor { 5 | public Object create(Token t) { 6 | return new MyAstNode(t); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /clonedigger/java_antlr/TreeProducer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/java_antlr/TreeProducer.jar -------------------------------------------------------------------------------- /clonedigger/java_antlr/TreeProducer.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2008 Peter Bulychev 2 | * 3 | * This file is part of Clone Digger. 4 | * 5 | * Clone Digger is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Clone Digger is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Clone Digger. If not, see . 17 | */ 18 | import org.antlr.runtime.*; 19 | import org.antlr.stringtemplate.*; 20 | import org.antlr.runtime.tree.*; 21 | import java.lang.reflect.*; 22 | import java.io.*; 23 | import java.util.*; 24 | import java.text.*; 25 | import java.lang.*; 26 | 27 | public class TreeProducer 28 | { 29 | public TreeProducer () 30 | { 31 | super (); 32 | } 33 | 34 | /* 35 | * forXml function was taken from http://www.javapractices.com/topic/TopicAction.do?Id=96 36 | * the license is: http://creativecommons.org/licenses/by/3.0/ 37 | */ 38 | public static String forXML (String aText) 39 | { 40 | final StringBuilder result = new StringBuilder (); 41 | final StringCharacterIterator iterator = 42 | new StringCharacterIterator (aText); 43 | char character = iterator.current (); 44 | while (character != CharacterIterator.DONE) 45 | { 46 | if (character == '<') 47 | { 48 | result.append ("<"); 49 | } 50 | else if (character == '>') 51 | { 52 | result.append (">"); 53 | } 54 | else if (character == '\"') 55 | { 56 | result.append ("""); 57 | } 58 | else if (character == '\'') 59 | { 60 | result.append ("'"); 61 | } 62 | else if (character == '&') 63 | { 64 | result.append ("&"); 65 | } 66 | else 67 | { 68 | //the char is not a special one 69 | // //add it to the result as is 70 | result.append (character); 71 | } 72 | character = iterator.next (); 73 | } 74 | return result.toString (); 75 | } 76 | // } 77 | 78 | public static void printTree (MyAstNode tree, PrintWriter outputStream, String indent) 79 | { 80 | String xml_node_name = (tree.is_statement?"statement_node":"node"); 81 | outputStream.println (indent + "<" + xml_node_name + " name=\"" + forXML ("" + tree) + "\"" + 82 | " line_number=\"" + tree.getLine () + "\" " + 83 | "start=\"" + ((CommonToken) tree.token).getStartIndex() + "\" " + 84 | "stop=\"" + ((CommonToken) tree.token).getStopIndex() + "\">"); 85 | for (int i = 0; i < tree.getChildCount (); i += 1) 86 | { 87 | printTree ((MyAstNode )tree.getChild (i), outputStream, indent + " "); 88 | } 89 | outputStream.println (indent + ""); 90 | } 91 | 92 | public static void main (String[]args) throws Exception 93 | { 94 | ANTLRFileStream input = new ANTLRFileStream (args[0]); 95 | JavaASTLexer lexer = new JavaASTLexer (input); 96 | CommonTokenStream tokens = new CommonTokenStream (lexer); 97 | JavaASTParser parser = new JavaASTParser (tokens); 98 | MyAstNodeAdaptor adaptor = new MyAstNodeAdaptor (); 99 | parser.setTreeAdaptor (adaptor); 100 | MyAstNode tree = (MyAstNode) parser.compilationUnit ().getTree (); 101 | PrintWriter outputStream = 102 | new PrintWriter (new FileWriter (args[1], false)); 103 | outputStream.println (""); 104 | printTree (tree, outputStream, ""); 105 | outputStream.close (); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /clonedigger/java_antlr/build_jar.sh: -------------------------------------------------------------------------------- 1 | java org.antlr.Tool JavaAST.g 2 | javac *.java 3 | jar -cf TreeProducer.jar *.class 4 | rm *.class 5 | -------------------------------------------------------------------------------- /clonedigger/js_antlr.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from __future__ import absolute_import 3 | from __future__ import unicode_literals 4 | from __future__ import division 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | from builtins import object 9 | # Copyright 2008 Peter Bulychev 10 | # http://clonedigger.sourceforge.net 11 | # 12 | # This file is part of Clone Digger. 13 | # 14 | # Clone Digger is free software: you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation, either version 3 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # Clone Digger is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with Clone Digger. If not, see . 26 | 27 | import os 28 | import xml.parsers.expat 29 | 30 | from .abstract_syntax_tree import * 31 | 32 | class JsANTLRSourceFile (SourceFile): 33 | extension = 'js' 34 | size_threshold = 5 35 | distance_threshold = 5 36 | def __init__(self, file_name): 37 | SourceFile.__init__(self, file_name) 38 | class ExpatHandler(object): 39 | def __init__(self, start_node, parent): 40 | self.parent = parent 41 | self.stack = [start_node] 42 | def start_element(expat_self, xml_node_name, attrs): 43 | line_number = int(attrs["line_number"])-1 44 | line_numbers = [line_number] 45 | if line_numbers == [-1]: 46 | line_numbers = [] 47 | name = attrs["name"] 48 | r = AbstractSyntaxTree(name, line_numbers, self) 49 | if xml_node_name == "statement_node": 50 | #if name in ["CALL", "BLOCK"]: 51 | r.markAsStatement() 52 | else: 53 | assert(xml_node_name == "node") 54 | expat_self.stack[-1].addChild(r) 55 | expat_self.stack.append(r) 56 | def end_element(self, name): 57 | self.stack.pop() 58 | 59 | tree_file_name = 'temporary_ast.xml' 60 | producer_class_path = os.path.join('.','js_antlr', 'TreeProducer.jar') 61 | antlr_class_path = os.path.join('.','antlr_runtime', 'antlr-3.1.1.jar') 62 | if os.name in ['mac', 'posix']: 63 | class_path_delimeter = ':' 64 | elif os.name in ['nt', 'dos', 'ce']: 65 | class_path_delimeter = ';' 66 | else: 67 | print('unsupported OS') 68 | assert(0) 69 | 70 | if os.system('java -classpath ' + producer_class_path + class_path_delimeter + antlr_class_path + ' TreeProducer %s %s 2>err.log'%(file_name, tree_file_name)): 71 | f = open('err.log') 72 | s = f.read() 73 | f.close() 74 | raise Exception(s) 75 | f = open('err.log') 76 | s = f.read() 77 | f.close() 78 | if s: 79 | print(s) 80 | 81 | self._tree = AbstractSyntaxTree('program') 82 | handler = ExpatHandler(self._tree, self) 83 | p = xml.parsers.expat.ParserCreate() 84 | p.StartElementHandler = handler.start_element 85 | p.EndElementHandler = handler.end_element 86 | f = open(tree_file_name) 87 | p.ParseFile(f) 88 | f.close() 89 | # os.remove(tree_file_name) 90 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/JavaScript.tokens: -------------------------------------------------------------------------------- 1 | BackslashSequence=168 2 | CONST=37 3 | COMMA=71 4 | RegularExpressionLiteral=155 5 | ARGS=111 6 | ARRAY=112 7 | LF=140 8 | SYNCHRONIZED=59 9 | HexDigit=150 10 | DOUBLE=39 11 | EXPR=118 12 | ADDASS=99 13 | DecimalDigit=152 14 | FALSE=6 15 | USP=138 16 | ABSTRACT=32 17 | SP=136 18 | DQUOTE=131 19 | IMPORT=47 20 | SEMIC=70 21 | MODASS=102 22 | PACKAGE=52 23 | SQUOTE=132 24 | SHR=87 25 | CONTINUE=10 26 | DOT=69 27 | PRIVATE=53 28 | MultiLineComment=146 29 | HexIntegerLiteral=161 30 | AND=89 31 | RegularExpressionFirstChar=169 32 | DIVASS=110 33 | FUNCTION=17 34 | GTE=75 35 | OctalEscapeSequence=164 36 | HexEscapeSequence=165 37 | SingleLineComment=147 38 | UnicodeEscapeSequence=166 39 | POS=129 40 | RPAREN=66 41 | IdentifierStartASCII=151 42 | FINALLY=15 43 | IdentifierNameASCIIStart=154 44 | EXTENDS=42 45 | IdentifierPart=153 46 | SUPER=58 47 | Identifier=148 48 | SAME=78 49 | CHAR=35 50 | NEW=21 51 | EQ=76 52 | LT=72 53 | FINAL=43 54 | SUBASS=100 55 | VT=134 56 | LAND=94 57 | LBRACK=67 58 | CATCH=9 59 | STATIC=57 60 | CASE=8 61 | MUL=82 62 | INTERFACE=49 63 | ExponentPart=157 64 | INV=93 65 | BOOLEAN=33 66 | ELSE=14 67 | CharacterEscapeSequence=162 68 | BSLASH=130 69 | SHLASS=103 70 | DecimalLiteral=159 71 | BREAK=7 72 | NULL=4 73 | XOR=91 74 | COLON=97 75 | DIV=109 76 | ORASS=107 77 | TRUE=5 78 | ADD=80 79 | THROW=25 80 | SHORT=56 81 | LABELLED=122 82 | CR=141 83 | RegularExpressionChar=170 84 | PUBLIC=55 85 | SHL=86 86 | LONG=50 87 | LOR=95 88 | TYPEOF=27 89 | INC=84 90 | TRANSIENT=61 91 | TAB=133 92 | FLOAT=44 93 | ZeroToThree=163 94 | THROWS=60 95 | FF=135 96 | FORITER=119 97 | GOTO=45 98 | MOD=83 99 | EXPORT=41 100 | OR=90 101 | MULASS=101 102 | LBRACE=63 103 | BLOCK=113 104 | RBRACE=64 105 | PROTECTED=54 106 | ANDASS=106 107 | LineTerminator=144 108 | SHU=88 109 | EscapeSequence=167 110 | PAREXPR=126 111 | INT=48 112 | LS=142 113 | CEXPR=117 114 | ASSIGN=98 115 | VOID=29 116 | INSTANCEOF=20 117 | LPAREN=65 118 | WhiteSpace=139 119 | XORASS=108 120 | QUE=96 121 | NEQ=77 122 | NAMEDVALUE=123 123 | ENUM=40 124 | PS=143 125 | DEBUGGER=38 126 | DELETE=12 127 | OBJECT=125 128 | DO=13 129 | IMPLEMENTS=46 130 | OctalIntegerLiteral=160 131 | WHILE=30 132 | SWITCH=23 133 | BYINDEX=115 134 | FORSTEP=120 135 | OctalDigit=156 136 | PINC=128 137 | GT=73 138 | StringLiteral=149 139 | DecimalIntegerLiteral=158 140 | SHRASS=104 141 | ITEM=121 142 | SHUASS=105 143 | THIS=24 144 | WITH=31 145 | IN=19 146 | VAR=28 147 | LTE=74 148 | CLASS=36 149 | NATIVE=51 150 | DEC=85 151 | RETURN=22 152 | BYTE=34 153 | VOLATILE=62 154 | IF=18 155 | EOL=145 156 | NBSP=137 157 | CALL=116 158 | FOR=16 159 | RBRACK=68 160 | DEFAULT=11 161 | NEG=124 162 | SUB=81 163 | NOT=92 164 | TRY=26 165 | PDEC=127 166 | BYFIELD=114 167 | NSAME=79 168 | '<'=72 169 | 'goto'=45 170 | '>'=73 171 | 'try'=26 172 | 'function'=17 173 | 'with'=31 174 | '-'=81 175 | '>>>='=105 176 | '?'=96 177 | '!='=77 178 | '>='=75 179 | 'do'=13 180 | '<<'=86 181 | 'double'=39 182 | '<='=74 183 | '='=98 184 | 'native'=51 185 | 'void'=29 186 | 'catch'=9 187 | ':'=97 188 | '*'=82 189 | '>>>'=88 190 | '<<='=103 191 | 'synchronized'=59 192 | 'true'=5 193 | 'false'=6 194 | ','=71 195 | '&&'=94 196 | 'this'=24 197 | 'continue'=10 198 | 'const'=37 199 | 'debugger'=38 200 | 'enum'=40 201 | 'return'=22 202 | ')'=66 203 | '=='=76 204 | 'static'=57 205 | 'implements'=46 206 | 'import'=47 207 | 'typeof'=27 208 | 'char'=35 209 | '!'=92 210 | '+='=99 211 | 'switch'=23 212 | 'delete'=12 213 | 'extends'=42 214 | '^='=108 215 | 'class'=36 216 | 'null'=4 217 | '+'=80 218 | 'interface'=49 219 | '-='=100 220 | 'case'=8 221 | 'boolean'=33 222 | 'else'=14 223 | '/='=110 224 | 'package'=52 225 | '%='=102 226 | 'var'=28 227 | '||'=95 228 | '*='=101 229 | 'volatile'=62 230 | 'instanceof'=20 231 | 'super'=58 232 | '|='=107 233 | '++'=84 234 | '{'=63 235 | 'throws'=60 236 | 'float'=44 237 | 'new'=21 238 | 'for'=16 239 | '.'=69 240 | 'short'=56 241 | '}'=64 242 | '~'=93 243 | 'finally'=15 244 | 'break'=7 245 | '%'=83 246 | 'final'=43 247 | ';'=70 248 | 'default'=11 249 | ']'=68 250 | '&'=89 251 | 'int'=48 252 | '!=='=79 253 | '&='=106 254 | 'while'=30 255 | '['=67 256 | '/'=109 257 | 'long'=50 258 | '^'=91 259 | 'private'=53 260 | '|'=90 261 | '>>='=104 262 | 'throw'=25 263 | 'protected'=54 264 | 'if'=18 265 | '('=65 266 | 'byte'=34 267 | 'transient'=61 268 | '==='=78 269 | '>>'=87 270 | '--'=85 271 | 'export'=41 272 | 'in'=19 273 | 'abstract'=32 274 | 'public'=55 275 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/MyAstNode.java: -------------------------------------------------------------------------------- 1 | import org.antlr.runtime.tree.*; 2 | import org.antlr.runtime.Token; 3 | 4 | import java.io.*; 5 | 6 | public class MyAstNode extends CommonTree { 7 | boolean is_statement = false; 8 | public MyAstNode(Token t) { 9 | super(t); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/MyAstNodeAdaptor.java: -------------------------------------------------------------------------------- 1 | import org.antlr.runtime.tree.*; 2 | import org.antlr.runtime.Token; 3 | 4 | class MyAstNodeAdaptor extends CommonTreeAdaptor { 5 | public Object create(Token t) { 6 | return new MyAstNode(t); 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/TreeProducer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/js_antlr/TreeProducer.jar -------------------------------------------------------------------------------- /clonedigger/js_antlr/TreeProducer.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2008 Peter Bulychev 2 | * 3 | * This file is part of Clone Digger. 4 | * 5 | * Clone Digger is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Clone Digger is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Clone Digger. If not, see . 17 | */ 18 | import org.antlr.runtime.*; 19 | import org.antlr.stringtemplate.*; 20 | import org.antlr.runtime.tree.*; 21 | import java.lang.reflect.*; 22 | import java.io.*; 23 | import java.util.*; 24 | import java.text.*; 25 | import java.lang.*; 26 | 27 | public class TreeProducer 28 | { 29 | public TreeProducer () 30 | { 31 | super (); 32 | } 33 | 34 | /* 35 | * forXml function was taken from http://www.javapractices.com/topic/TopicAction.do?Id=96 36 | * the license is: http://creativecommons.org/licenses/by/3.0/ 37 | */ 38 | public static String forXML (String aText) 39 | { 40 | final StringBuilder result = new StringBuilder (); 41 | final StringCharacterIterator iterator = 42 | new StringCharacterIterator (aText); 43 | char character = iterator.current (); 44 | while (character != CharacterIterator.DONE) 45 | { 46 | if (character == '<') 47 | { 48 | result.append ("<"); 49 | } 50 | else if (character == '>') 51 | { 52 | result.append (">"); 53 | } 54 | else if (character == '\"') 55 | { 56 | result.append ("""); 57 | } 58 | else if (character == '\'') 59 | { 60 | result.append ("'"); 61 | } 62 | else if (character == '&') 63 | { 64 | result.append ("&"); 65 | } 66 | else 67 | { 68 | //the char is not a special one 69 | // //add it to the result as is 70 | result.append (character); 71 | } 72 | character = iterator.next (); 73 | } 74 | return result.toString (); 75 | } 76 | // } 77 | 78 | public static void printTree (MyAstNode tree, PrintWriter outputStream, String indent) 79 | { 80 | String xml_node_name = (tree.is_statement?"statement_node":"node"); 81 | int start_index; 82 | int stop_index; 83 | if (tree.token == null) { 84 | // Sometimes we get the 'nil' node when parsering compressed JS, 85 | start_index = 0; 86 | stop_index = 0; 87 | } else { 88 | start_index = ((CommonToken) tree.token).getStartIndex(); 89 | stop_index = ((CommonToken) tree.token).getStopIndex(); 90 | } 91 | outputStream.println (indent + "<" + xml_node_name + " name=\"" + forXML ("" + tree) + "\"" + 92 | " line_number=\"" + tree.getLine () + "\" " + 93 | "start=\"" + start_index + "\" " + 94 | "stop=\"" + stop_index + "\">"); 95 | 96 | for (int i = 0; i < tree.getChildCount (); i += 1) 97 | { 98 | printTree ((MyAstNode )tree.getChild (i), outputStream, indent + " "); 99 | } 100 | outputStream.println (indent + ""); 101 | } 102 | 103 | public static void main (String[]args) throws Exception 104 | { 105 | ANTLRFileStream input = new ANTLRFileStream (args[0]); 106 | JavaScriptLexer lexer = new JavaScriptLexer (input); 107 | CommonTokenStream tokens = new CommonTokenStream (lexer); 108 | JavaScriptParser parser = new JavaScriptParser (tokens); 109 | MyAstNodeAdaptor adaptor = new MyAstNodeAdaptor (); 110 | parser.setTreeAdaptor (adaptor); 111 | MyAstNode tree = (MyAstNode) parser.program ().getTree (); 112 | PrintWriter outputStream = 113 | new PrintWriter (new FileWriter (args[1], false)); 114 | outputStream.println (""); 115 | printTree (tree, outputStream, ""); 116 | outputStream.close (); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/build_jar.sh: -------------------------------------------------------------------------------- 1 | java org.antlr.Tool JavaScript.g 2 | javac *.java 3 | jar -cf TreeProducer.jar *.class 4 | rm *.class 5 | -------------------------------------------------------------------------------- /clonedigger/js_antlr/license.txt: -------------------------------------------------------------------------------- 1 | Software License Agreement (BSD License) 2 | 3 | Copyright (c) 2008, Xebic Research B.V. 4 | All rights reserved. 5 | 6 | Redistribution and use of this software in source and binary forms, with or without modification, are 7 | permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above 10 | copyright notice, this list of conditions and the 11 | following disclaimer. 12 | 13 | * Redistributions in binary form must reproduce the above 14 | copyright notice, this list of conditions and the 15 | following disclaimer in the documentation and/or other 16 | materials provided with the distribution. 17 | 18 | * Neither the name of Xebic Research B.V. nor the names of its 19 | contributors may be used to endorse or promote products 20 | derived from this software without specific prior 21 | written permission of Xebic Research B.V. 22 | 23 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 24 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 25 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 29 | TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 30 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /clonedigger/logilab/__init__.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from __future__ import print_function 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | pass 9 | -------------------------------------------------------------------------------- /clonedigger/logilab/astng/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # pylint: disable-msg=W0622 2 | # 3 | # Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). 4 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 5 | # 6 | # This program is free software; you can redistribute it and/or modify it under 7 | # the terms of the GNU General Public License as published by the Free Software 8 | # Foundation; either version 2 of the License, or (at your option) any later 9 | # version. 10 | # 11 | # This program is distributed in the hope that it will be useful, but WITHOUT 12 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 14 | # 15 | # You should have received a copy of the GNU General Public License along with 16 | # this program; if not, write to the Free Software Foundation, Inc., 17 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | """ 19 | logilab.astng packaging information 20 | """ 21 | from __future__ import unicode_literals 22 | from __future__ import print_function 23 | from __future__ import division 24 | from __future__ import absolute_import 25 | from future import standard_library 26 | standard_library.install_aliases() 27 | from builtins import str 28 | from builtins import * 29 | 30 | modname = 'astng' 31 | distname = 'logilab-astng' 32 | numversion = (0, 17, 2) 33 | version = '.'.join([str(num) for num in numversion]) 34 | pyversions = ["2.3", "2.4", "2.5"] 35 | 36 | license = 'GPL' 37 | copyright = '''Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). 38 | http://www.logilab.fr/ -- mailto:contact@logilab.fr''' 39 | 40 | author = 'Sylvain Thenault' 41 | author_email = 'sylvain.thenault@logilab.fr' 42 | 43 | short_desc = "extend python's abstract syntax tree" 44 | 45 | long_desc = """The aim of this module is to provide a common base \ 46 | representation of 47 | python source code for projects such as pychecker, pyreverse, 48 | pylint... Well, actually the development of this library is essentialy 49 | governed by pylint's needs. 50 | 51 | It extends class defined in the compiler.ast [1] module with some 52 | additional methods and attributes. Instance attributes are added by a 53 | builder object, which can either generate extended ast (let's call 54 | them astng ;) by visiting an existant ast tree or by inspecting living 55 | object. Methods are added by monkey patching ast classes.""" 56 | 57 | 58 | web = "http://www.logilab.org/project/name/%s" % distname 59 | ftp = "ftp://ftp.logilab.org/pub/%s" % modname 60 | mailinglist = "mailto://python-projects@lists.logilab.org" 61 | 62 | subpackage_of = 'logilab' 63 | 64 | from os.path import join 65 | include_dirs = [join('test', 'regrtest_data'), 66 | join('test', 'data'), join('test', 'data2')] 67 | 68 | debian_uploader = 'Alexandre Fayolle ' 69 | -------------------------------------------------------------------------------- /clonedigger/logilab/astng/_exceptions.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """this module contains exceptions used in the astng library 14 | 15 | :author: Sylvain Thenault 16 | :copyright: 2003-2007 LOGILAB S.A. (Paris, FRANCE) 17 | :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org 18 | :copyright: 2003-2007 Sylvain Thenault 19 | :contact: mailto:thenault@gmail.com 20 | """ 21 | from __future__ import unicode_literals 22 | from __future__ import print_function 23 | from __future__ import division 24 | from __future__ import absolute_import 25 | from future import standard_library 26 | standard_library.install_aliases() 27 | from builtins import * 28 | 29 | __doctype__ = "restructuredtext en" 30 | 31 | class ASTNGError(Exception): 32 | """base exception class for all astng related exceptions 33 | """ 34 | 35 | class ASTNGBuildingException(ASTNGError): 36 | """exception class when we are not able to build an astng representation""" 37 | 38 | class ResolveError(ASTNGError): 39 | """base class of astng resolution/inference error""" 40 | 41 | class NotFoundError(ResolveError): 42 | """raised when we are unabled to resolve a name""" 43 | 44 | class InferenceError(ResolveError): 45 | """raised when we are unabled to infer a node""" 46 | 47 | class UnresolvableName(InferenceError): 48 | """raised when we are unabled to resolve a name""" 49 | 50 | 51 | class NoDefault(ASTNGError): 52 | """raised by function's `default_value` method when an argument has 53 | no default value 54 | """ 55 | 56 | class IgnoreChild(Exception): 57 | """exception that maybe raised by visit methods to avoid children traversal 58 | """ 59 | 60 | -------------------------------------------------------------------------------- /clonedigger/logilab/astng/astutils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003 Sylvain Thenault (thenault@nerim.net) 2 | # Copyright (c) 2003 Logilab 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """Some usefull functions to manipulate ast tuples 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import map 25 | from builtins import * 26 | 27 | __author__ = u"Sylvain Thenault" 28 | 29 | import symbol 30 | import token 31 | from types import TupleType 32 | 33 | def debuild(ast_tuple): 34 | """ 35 | reverse ast_tuple to string 36 | """ 37 | if type(ast_tuple[1]) is TupleType: 38 | result = '' 39 | for child in ast_tuple[1:]: 40 | result = '%s%s' % (result, debuild(child)) 41 | return result 42 | else: 43 | return ast_tuple[1] 44 | 45 | def clean(ast_tuple): 46 | """ 47 | reverse ast tuple to a list of tokens 48 | merge sequences (token.NAME, token.DOT, token.NAME) 49 | """ 50 | result = [] 51 | last = None 52 | for couple in _clean(ast_tuple): 53 | if couple[0] == token.NAME and last == token.DOT: 54 | result[-1][1] += couple[1] 55 | elif couple[0] == token.DOT and last == token.NAME: 56 | result[-1][1] += couple[1] 57 | else: 58 | result.append(couple) 59 | last = couple[0] 60 | return result 61 | 62 | def _clean(ast_tuple): 63 | """ transform the ast into as list of tokens (i.e. final elements) 64 | """ 65 | if type(ast_tuple[1]) is TupleType: 66 | v = [] 67 | for c in ast_tuple[1:]: 68 | v += _clean(c) 69 | return v 70 | else: 71 | return [list(ast_tuple[:2])] 72 | 73 | def cvrtr(tuple): 74 | """debug method returning an ast string in a readable fashion""" 75 | if type(tuple) is TupleType: 76 | try: 77 | try: 78 | txt = 'token.'+token.tok_name[tuple[0]] 79 | except: 80 | txt = 'symbol.'+symbol.sym_name[tuple[0]] 81 | except: 82 | txt = 'Unknown token/symbol' 83 | return [txt] + list(map(cvrtr, tuple[1:])) 84 | else: 85 | return tuple 86 | 87 | __all__ = ('debuild', 'clean', 'cvrtr') 88 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/__init__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003-2006 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """Logilab common libraries: 17 | 18 | a set of common functionnalities shared among logilab projects 19 | 20 | 21 | :type STD_BLACKLIST: tuple 22 | :var STD_BLACKLIST: 23 | directories ignored by default by the functions in this package which have 24 | to recurse into directories 25 | 26 | :type IGNORED_EXTENSIONS: tuple 27 | :var IGNORED_EXTENSIONS: 28 | file extensions that may usually be ignored 29 | """ 30 | from __future__ import division 31 | from __future__ import unicode_literals 32 | from __future__ import print_function 33 | from __future__ import absolute_import 34 | from future import standard_library 35 | standard_library.install_aliases() 36 | from builtins import range 37 | from builtins import * 38 | from past.utils import old_div 39 | from builtins import object 40 | 41 | STD_BLACKLIST = ('CVS', '.svn', '.hg', 'debian', 'dist', 'build') 42 | 43 | IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc', '~') 44 | 45 | 46 | 47 | from clonedigger.logilab.common.deprecation import moved 48 | 49 | get_cycles = moved('logilab.common.graph', 'get_cycles') 50 | cached = moved('logilab.common.decorators', 'cached') 51 | ProgressBar = moved('logilab.common.shellutils', 'ProgressBar') 52 | Execute = moved('logilab.common.shellutils', 'Execute') 53 | acquire_lock = moved('logilab.common.shellutils', 'acquire_lock') 54 | release_lock = moved('logilab.common.shellutils', 'release_lock') 55 | deprecated_function = moved('logilab.common.deprecation', 'deprecated_function') 56 | class_renamed = moved('logilab.common.deprecation', 'class_renamed') 57 | 58 | def intersection(list1, list2): 59 | """return the intersection of list1 and list2""" 60 | warn('this function is deprecated, use a set instead', DeprecationWarning, 61 | stacklevel=2) 62 | intersect_dict, result = {}, [] 63 | for item in list1: 64 | intersect_dict[item] = 1 65 | for item in list2: 66 | if item in intersect_dict: 67 | result.append(item) 68 | return result 69 | 70 | def difference(list1, list2): 71 | """return elements of list1 not in list2""" 72 | warn('this function is deprecated, use a set instead', DeprecationWarning, 73 | stacklevel=2) 74 | tmp, result = {}, [] 75 | for i in list2: 76 | tmp[i] = 1 77 | for i in list1: 78 | if i not in tmp: 79 | result.append(i) 80 | return result 81 | 82 | def union(list1, list2): 83 | """return list1 union list2""" 84 | warn('this function is deprecated, use a set instead', DeprecationWarning, 85 | stacklevel=2) 86 | tmp = {} 87 | for i in list1: 88 | tmp[i] = 1 89 | for i in list2: 90 | tmp[i] = 1 91 | return list(tmp.keys()) 92 | 93 | 94 | class attrdict(dict): 95 | """a dictionary whose keys are also accessible as attributes""" 96 | def __getattr__(self, attr): 97 | try: 98 | return self[attr] 99 | except KeyError: 100 | raise AttributeError(attr) 101 | 102 | class nullobject(object): 103 | def __bool__(self): 104 | return False 105 | 106 | # flatten ----- 107 | # XXX move in a specific module and use yield instead 108 | # do not mix flatten and translate 109 | # 110 | # def iterable(obj): 111 | # try: iter(obj) 112 | # except: return False 113 | # return True 114 | # 115 | # def is_string_like(obj): 116 | # try: obj +'' 117 | # except (TypeError, ValueError): return False 118 | # return True 119 | # 120 | #def is_scalar(obj): 121 | # return is_string_like(obj) or not iterable(obj) 122 | # 123 | #def flatten(seq): 124 | # for item in seq: 125 | # if is_scalar(item): 126 | # yield item 127 | # else: 128 | # for subitem in flatten(item): 129 | # yield subitem 130 | 131 | def flatten(iterable, tr_func=None, results=None): 132 | """flatten a list of list with any level 133 | 134 | if tr_func is not None, it should be a one argument function that'll be called 135 | on each final element 136 | """ 137 | if results is None: 138 | results = [] 139 | for val in iterable: 140 | if isinstance(val, (list, tuple)): 141 | flatten(val, tr_func, results) 142 | elif tr_func is None: 143 | results.append(val) 144 | else: 145 | results.append(tr_func(val)) 146 | return results 147 | 148 | 149 | # XXX is function below still used ? 150 | 151 | def make_domains(lists): 152 | """ 153 | given a list of lists, return a list of domain for each list to produce all 154 | combinaisons of possibles values 155 | 156 | ex: (['a', 'b'], ['c','d', 'e']) 157 | -> (['a', 'b', 'a', 'b', 'a', 'b'], 158 | ['c', 'c', 'd', 'd', 'e', 'e']) 159 | """ 160 | domains = [] 161 | for iterable in lists: 162 | new_domain = iterable[:] 163 | for i in range(len(domains)): 164 | domains[i] = domains[i]*len(iterable) 165 | if domains: 166 | missing = old_div((len(domains[0]) - len(iterable)), len(iterable)) 167 | i = 0 168 | for j in range(len(iterable)): 169 | value = iterable[j] 170 | for dummy in range(missing): 171 | new_domain.insert(i, value) 172 | i += 1 173 | i += 1 174 | domains.append(new_domain) 175 | return domains 176 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/__pkginfo__.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """logilab.common packaging information""" 17 | from __future__ import unicode_literals 18 | from __future__ import print_function 19 | from __future__ import division 20 | from __future__ import absolute_import 21 | from future import standard_library 22 | standard_library.install_aliases() 23 | from builtins import str 24 | from builtins import * 25 | 26 | distname = 'logilab-common' 27 | modname = 'common' 28 | numversion = (0, 31, 0) 29 | version = '.'.join([str(num) for num in numversion]) 30 | 31 | license = 'GPL' 32 | copyright = '''Copyright (c) 2003-2008 LOGILAB S.A. (Paris, FRANCE). 33 | http://www.logilab.fr/ -- mailto:contact@logilab.fr''' 34 | 35 | author = "Logilab" 36 | author_email = "devel@logilab.fr" 37 | 38 | short_desc = "useful miscellaneous modules used by Logilab projects" 39 | 40 | long_desc = """logilab-common is a collection of low-level Python packages and \ 41 | modules, 42 | designed to ease: 43 | * handling command line options and configuration files 44 | * writing interactive command line tools 45 | * manipulation files and character strings 46 | * interfacing to OmniORB 47 | * generating of SQL queries 48 | * running unit tests 49 | * manipulating tree structures 50 | * accessing RDBMS (currently postgreSQL, mysql and sqlite) 51 | * generating text and HTML reports 52 | * logging""" 53 | 54 | 55 | web = "http://www.logilab.org/project/%s" % distname 56 | ftp = "ftp://ftp.logilab.org/pub/%s" % modname 57 | mailinglist = "mailto://python-projects@lists.logilab.org" 58 | 59 | subpackage_of = 'logilab' 60 | subpackage_master = True 61 | 62 | scripts = ('bin/pytest',) 63 | from os.path import join 64 | include_dirs = [join('test', 'data')] 65 | pyversions = ['2.3', '2.4', '2.5'] 66 | debian_maintainer = 'Alexandre Fayolle' 67 | debian_maintainer_email = 'afayolle@debian.org' 68 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/astutils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2003 Sylvain Thenault (thenault@nerim.net) 2 | # Copyright (c) 2003 Logilab 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """Some usefull functions to manipulate ast tuples 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import map 25 | from builtins import * 26 | 27 | from warnings import warn 28 | warn('this module has been moved into logilab.astng and will disappear from \ 29 | logilab.common in a future release', 30 | DeprecationWarning, stacklevel=1) 31 | 32 | __author__ = u"Sylvain Thenault" 33 | 34 | import symbol 35 | import token 36 | from types import TupleType 37 | 38 | def debuild(ast_tuple): 39 | """ 40 | reverse ast_tuple to string 41 | """ 42 | if type(ast_tuple[1]) is TupleType: 43 | result = '' 44 | for child in ast_tuple[1:]: 45 | result = '%s%s' % (result, debuild(child)) 46 | return result 47 | else: 48 | return ast_tuple[1] 49 | 50 | def clean(ast_tuple): 51 | """ 52 | reverse ast tuple to a list of tokens 53 | merge sequences (token.NAME, token.DOT, token.NAME) 54 | """ 55 | result = [] 56 | last = None 57 | for couple in _clean(ast_tuple): 58 | if couple[0] == token.NAME and last == token.DOT: 59 | result[-1][1] += couple[1] 60 | elif couple[0] == token.DOT and last == token.NAME: 61 | result[-1][1] += couple[1] 62 | else: 63 | result.append(couple) 64 | last = couple[0] 65 | return result 66 | 67 | def _clean(ast_tuple): 68 | """ transform the ast into as list of tokens (i.e. final elements) 69 | """ 70 | if type(ast_tuple[1]) is TupleType: 71 | v = [] 72 | for c in ast_tuple[1:]: 73 | v += _clean(c) 74 | return v 75 | else: 76 | return [list(ast_tuple[:2])] 77 | 78 | def cvrtr(tuple): 79 | """debug method returning an ast string in a readable fashion""" 80 | if type(tuple) is TupleType: 81 | try: 82 | try: 83 | txt = 'token.'+token.tok_name[tuple[0]] 84 | except: 85 | txt = 'symbol.'+symbol.sym_name[tuple[0]] 86 | except: 87 | txt = 'Unknown token/symbol' 88 | return [txt] + list(map(cvrtr, tuple[1:])) 89 | else: 90 | return tuple 91 | 92 | __all__ = ('debuild', 'clean', 'cvrtr') 93 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/cache.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2002-2003 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | 16 | Cache module, with a least recently used algorithm for the management of the 17 | deletion of entries. 18 | """ 19 | from __future__ import unicode_literals 20 | from __future__ import print_function 21 | from __future__ import division 22 | from __future__ import absolute_import 23 | from future import standard_library 24 | standard_library.install_aliases() 25 | from builtins import * 26 | from builtins import object 27 | 28 | _marker = object() 29 | 30 | class Cache(object): 31 | """ a dictionnary like cache 32 | 33 | inv: 34 | len(self._usage) <= self.size 35 | len(self.data) <= self.size 36 | """ 37 | 38 | def __init__(self, size=100): 39 | self.data = {} 40 | self.size = size 41 | self._usage = [] 42 | 43 | def __repr__(self): 44 | return repr(self.data) 45 | 46 | def __len__(self): 47 | return len(self.data) 48 | 49 | def _update_usage(self, key): 50 | # Special case : cache's size = 0 ! 51 | if self.size <= 0: 52 | return 53 | 54 | if not self._usage: 55 | self._usage.append(key) 56 | 57 | elif self._usage[-1] != key: 58 | try: 59 | self._usage.remove(key) 60 | except ValueError: 61 | # we are inserting a new key 62 | # check the size of the dictionnary 63 | # and remove the oldest item in the cache 64 | if self.size and len(self._usage) >= self.size: 65 | del self.data[self._usage[0]] 66 | del self._usage[0] 67 | self._usage.append(key) 68 | else: 69 | pass # key is already the most recently used key 70 | 71 | 72 | def __getitem__(self, key): 73 | value = self.data[key] 74 | self._update_usage(key) 75 | return value 76 | 77 | def __setitem__(self, key, item): 78 | # Just make sure that size > 0 before inserting a new item in the cache 79 | if self.size > 0: 80 | self.data[key] = item 81 | self._update_usage(key) 82 | 83 | def __delitem__(self, key): 84 | # If size <= 0, then we don't have anything to do 85 | # XXX FIXME : Should we let the 'del' raise a KeyError ? 86 | if self.size > 0: 87 | del self.data[key] 88 | self._usage.remove(key) 89 | 90 | def pop(self, value, default=_marker): 91 | if value in self.data: 92 | self._usage.remove(value) 93 | if default is _marker: 94 | return self.data.pop(value) 95 | return self.data.pop(value, default) 96 | 97 | def clear(self): 98 | self.data.clear() 99 | self._usage = [] 100 | 101 | def keys(self): 102 | return list(self.data.keys()) 103 | 104 | def items(self): 105 | return list(self.data.items()) 106 | 107 | def values(self): 108 | return list(self.data.values()) 109 | 110 | def has_key(self, key): 111 | return key in self.data 112 | 113 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/clcommands.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """provides helper functions to handle a command line tool providing more than 14 | one command 15 | e.g called as "tool command [options] args..." where and are 16 | command'specific 17 | 18 | :author: Logilab 19 | :copyright: 2003-2008 LOGILAB S.A. (Paris, FRANCE) 20 | :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org 21 | """ 22 | from __future__ import print_function 23 | from __future__ import unicode_literals 24 | from __future__ import division 25 | from __future__ import absolute_import 26 | from future import standard_library 27 | standard_library.install_aliases() 28 | from builtins import * 29 | 30 | # XXX : merge with optparser ? 31 | import sys 32 | from os.path import basename 33 | 34 | from clonedigger.logilab.common.configuration import Configuration 35 | 36 | 37 | DEFAULT_COPYRIGHT = '''\ 38 | Copyright (c) 2004-2008 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 39 | http://www.logilab.fr/ -- mailto:contact@logilab.fr''' 40 | 41 | 42 | class BadCommandUsage(Exception): 43 | """Raised when an unknown command is used or when a command is not 44 | correctly used 45 | """ 46 | 47 | 48 | class Command(Configuration): 49 | """base class for command line commands""" 50 | arguments = '' 51 | name = '' 52 | # hidden from help ? 53 | hidden = False 54 | # max/min args, None meaning unspecified 55 | min_args = None 56 | max_args = None 57 | def __init__(self, __doc__=None, version=None): 58 | if __doc__: 59 | usage = __doc__ % (self.name, self.arguments, 60 | self.__doc__.replace(' ', '')) 61 | else: 62 | usage = self.__doc__.replace(' ', '') 63 | Configuration.__init__(self, usage=usage, version=version) 64 | 65 | def check_args(self, args): 66 | """check command's arguments are provided""" 67 | if self.min_args is not None and len(args) < self.min_args: 68 | raise BadCommandUsage('missing argument') 69 | if self.max_args is not None and len(args) > self.max_args: 70 | raise BadCommandUsage('too many arguments') 71 | 72 | def run(self, args): 73 | """run the command with its specific arguments""" 74 | raise NotImplementedError() 75 | 76 | 77 | def pop_arg(args_list, expected_size_after=0, msg="Missing argument"): 78 | """helper function to get and check command line arguments""" 79 | try: 80 | value = args_list.pop(0) 81 | except IndexError: 82 | raise BadCommandUsage(msg) 83 | if expected_size_after is not None and len(args_list) > expected_size_after: 84 | raise BadCommandUsage('Too much arguments') 85 | return value 86 | 87 | 88 | _COMMANDS = {} 89 | 90 | def register_commands(commands): 91 | """register existing commands""" 92 | for command_klass in commands: 93 | _COMMANDS[command_klass.name] = command_klass 94 | 95 | 96 | def main_usage(status=0, __doc__=None, copyright=DEFAULT_COPYRIGHT): 97 | """display usage for the main program (ie when no command supplied) 98 | and exit 99 | """ 100 | commands = list(_COMMANDS.keys()) 101 | commands.sort() 102 | doc = __doc__ % ('', '', 103 | '''\ 104 | Type "%prog --help" for more information about a specific 105 | command. Available commands are :\n''') 106 | doc = doc.replace('%prog', basename(sys.argv[0])) 107 | print('usage:', doc) 108 | max_len = max([len(cmd) for cmd in commands]) # list comprehension for py 2.3 support 109 | padding = ' '*max_len 110 | for command in commands: 111 | cmd = _COMMANDS[command] 112 | if not cmd.hidden: 113 | title = cmd.__doc__.split('.')[0] 114 | print(' ', (command+padding)[:max_len], title) 115 | print('\n', copyright) 116 | sys.exit(status) 117 | 118 | 119 | def cmd_run(cmdname, *args): 120 | try: 121 | command = _COMMANDS[cmdname](__doc__='%%prog %s %s\n\n%s') 122 | except KeyError: 123 | raise BadCommandUsage('no %s command' % cmdname) 124 | args = command.load_command_line_configuration(args) 125 | command.check_args(args) 126 | try: 127 | command.run(args) 128 | except KeyboardInterrupt: 129 | print('interrupted') 130 | except BadCommandUsage as err: 131 | print('ERROR: ', err) 132 | print(command.help()) 133 | 134 | 135 | def main_run(args, doc): 136 | """command line tool""" 137 | try: 138 | arg = args.pop(0) 139 | except IndexError: 140 | main_usage(status=1, __doc__=doc) 141 | if arg in ('-h', '--help'): 142 | main_usage(__doc__=doc) 143 | try: 144 | cmd_run(arg, *args) 145 | except BadCommandUsage as err: 146 | print('ERROR: ', err) 147 | main_usage(1, doc) 148 | 149 | 150 | class ListCommandsCommand(Command): 151 | """list available commands, useful for bash completion.""" 152 | name = 'listcommands' 153 | arguments = '[command]' 154 | hidden = True 155 | 156 | def run(self, args): 157 | """run the command with its specific arguments""" 158 | if args: 159 | command = pop_arg(args) 160 | cmd = _COMMANDS[command] 161 | for optname, optdict in cmd.options: 162 | print('--help') 163 | print('--' + optname) 164 | else: 165 | commands = list(_COMMANDS.keys()) 166 | commands.sort() 167 | for command in commands: 168 | cmd = _COMMANDS[command] 169 | if not cmd.hidden: 170 | print(command) 171 | 172 | register_commands([ListCommandsCommand]) 173 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/corbautils.py: -------------------------------------------------------------------------------- 1 | """A set of utility function to ease the use of OmniORBpy.""" 2 | from __future__ import unicode_literals 3 | from __future__ import print_function 4 | from __future__ import division 5 | from __future__ import absolute_import 6 | from future import standard_library 7 | standard_library.install_aliases() 8 | from builtins import * 9 | 10 | __revision__ = '$Id: corbautils.py,v 1.2 2005-11-22 13:13:00 syt Exp $' 11 | 12 | from omniORB import CORBA, PortableServer 13 | import CosNaming 14 | 15 | orb = None 16 | 17 | def get_orb(): 18 | """ 19 | returns a reference to the ORB. 20 | The first call to the method initialized the ORB 21 | This method is mainly used internally in the module. 22 | """ 23 | 24 | global orb 25 | if orb is None: 26 | import sys 27 | orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID) 28 | return orb 29 | 30 | def get_root_context(): 31 | """ 32 | returns a reference to the NameService object. 33 | This method is mainly used internally in the module. 34 | """ 35 | 36 | orb = get_orb() 37 | nss = orb.resolve_initial_references("NameService") 38 | rootContext = nss._narrow(CosNaming.NamingContext) 39 | assert rootContext is not None,"Failed to narrow root naming context" 40 | return rootContext 41 | 42 | def register_object_name(object, namepath): 43 | """ 44 | Registers a object in the NamingService. 45 | The name path is a list of 2-uples (id,kind) giving the path. 46 | 47 | For instance if the path of an object is [('foo',''),('bar','')], 48 | it is possible to get a reference to the object using the URL 49 | 'corbaname::hostname#foo/bar'. 50 | [('logilab','rootmodule'),('chatbot','application'),('chatter','server')] 51 | is mapped to 52 | 'corbaname::hostname#logilab.rootmodule/chatbot.application/chatter.server' 53 | 54 | The get_object_reference() function can be used to resolve such a URL. 55 | """ 56 | context = get_root_context() 57 | for id, kind in namepath[:-1]: 58 | name = [CosNaming.NameComponent(id, kind)] 59 | try: 60 | context = context.bind_new_context(name) 61 | except CosNaming.NamingContext.AlreadyBound as ex: 62 | context = context.resolve(name)._narrow(CosNaming.NamingContext) 63 | assert context is not None, \ 64 | 'test context exists but is not a NamingContext' 65 | 66 | id,kind = namepath[-1] 67 | name = [CosNaming.NameComponent(id, kind)] 68 | try: 69 | context.bind(name, object._this()) 70 | except CosNaming.NamingContext.AlreadyBound as ex: 71 | context.rebind(name, object._this()) 72 | 73 | def activate_POA(): 74 | """ 75 | This methods activates the Portable Object Adapter. 76 | You need to call it to enable the reception of messages in your code, 77 | on both the client and the server. 78 | """ 79 | orb = get_orb() 80 | poa = orb.resolve_initial_references('RootPOA') 81 | poaManager = poa._get_the_POAManager() 82 | poaManager.activate() 83 | 84 | def run_orb(): 85 | """ 86 | Enters the ORB mainloop on the server. 87 | You should not call this method on the client. 88 | """ 89 | get_orb().run() 90 | 91 | def get_object_reference(url): 92 | """ 93 | Resolves a corbaname URL to an object proxy. 94 | See register_object_name() for examples URLs 95 | """ 96 | return get_orb().string_to_object(url) 97 | 98 | def get_object_string(host, namepath): 99 | """given an host name and a name path as described in register_object_name, 100 | return a corba string identifier 101 | """ 102 | strname = '/'.join(['.'.join(path_elt) for path_elt in namepath]) 103 | return 'corbaname::%s#%s' % (host, strname) 104 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/daemon.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2002-2003 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | 16 | a daemon mix-in class 17 | """ 18 | from __future__ import print_function 19 | from __future__ import unicode_literals 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import str 25 | from builtins import * 26 | from builtins import object 27 | 28 | __revision__ = '$Id: daemon.py,v 1.10 2005-11-22 13:13:01 syt Exp $' 29 | 30 | import os, signal, sys, time 31 | from clonedigger.logilab.common.logger import make_logger, LOG_ALERT, LOG_NOTICE 32 | 33 | class DaemonMixIn(object): 34 | """ mixin to make a daemon from watchers/queriers 35 | """ 36 | 37 | def __init__(self, configmod) : 38 | self.delay = configmod.DELAY 39 | self.name = str(self.__class__).split('.')[-1] 40 | self._pid_file = os.path.join('/tmp', '%s.pid'%self.name) 41 | if os.path.exists(self._pid_file): 42 | raise Exception('''Another instance of %s must be running. 43 | If it i not the case, remove the file %s''' % (self.name, self._pid_file)) 44 | self._alive = 1 45 | self._sleeping = 0 46 | treshold = configmod.LOG_TRESHOLD 47 | if configmod.NODETACH: 48 | configmod.log = make_logger('print', treshold, self.name).log 49 | else: 50 | configmod.log = make_logger('syslog', treshold, self.name).log 51 | self.config = configmod 52 | 53 | def _daemonize(self): 54 | if not self.config.NODETACH: 55 | # fork so the parent can exist 56 | if (os.fork()): 57 | return -1 58 | # deconnect from tty and create a new session 59 | os.setsid() 60 | # fork again so the parent, (the session group leader), can exit. 61 | # as a non-session group leader, we can never regain a controlling 62 | # terminal. 63 | if (os.fork()): 64 | return -1 65 | # move to the root to avoit mount pb 66 | os.chdir('/') 67 | # set paranoid umask 68 | os.umask(0o77) 69 | # write pid in a file 70 | f = open(self._pid_file, 'w') 71 | f.write(str(os.getpid())) 72 | f.close() 73 | # close standard descriptors 74 | sys.stdin.close() 75 | sys.stdout.close() 76 | sys.stderr.close() 77 | # put signal handler 78 | signal.signal(signal.SIGTERM, self.signal_handler) 79 | signal.signal(signal.SIGHUP, self.signal_handler) 80 | 81 | 82 | def run(self): 83 | """ optionaly go in daemon mode and 84 | do what concrete classe has to do and pauses for delay between runs 85 | If self.delay is negative, do a pause before starting 86 | """ 87 | if self._daemonize() == -1: 88 | return 89 | self.config.log(LOG_NOTICE, '%s instance started' % self.name) 90 | if self.delay < 0: 91 | self.delay = -self.delay 92 | time.sleep(self.delay) 93 | while 1: 94 | try: 95 | self._run() 96 | except Exception as e: 97 | # display for info, sleep, and hope the problem will be solved 98 | # later. 99 | self.config.log(LOG_ALERT, 'Internal error: %s'%(e)) 100 | if not self._alive: 101 | break 102 | try: 103 | self._sleeping = 1 104 | time.sleep(self.delay) 105 | self._sleeping = 0 106 | except SystemExit: 107 | break 108 | self.config.log(LOG_NOTICE, '%s instance exited'%self.name) 109 | # remove pid file 110 | os.remove(self._pid_file) 111 | 112 | def signal_handler(self, sig_num, stack_frame): 113 | if sig_num == signal.SIGTERM: 114 | if self._sleeping: 115 | # we are sleeping so we can exit without fear 116 | self.config.log(LOG_NOTICE, 'exit on SIGTERM') 117 | sys.exit(0) 118 | else: 119 | self.config.log(LOG_NOTICE, 'exit on SIGTERM (on next turn)') 120 | self._alive = 0 121 | elif sig_num == signal.SIGHUP: 122 | self.config.log(LOG_NOTICE, 'reloading configuration on SIGHUP') 123 | reload(self.config) 124 | 125 | def _run(self): 126 | """should be overidden in the mixed class""" 127 | raise NotImplementedError() 128 | 129 | ## command line utilities ###################################################### 130 | 131 | L_OPTIONS = ["help", "log=", "delay=", 'no-detach'] 132 | S_OPTIONS = 'hl:d:n' 133 | 134 | def print_help(modconfig): 135 | print(""" --help or -h 136 | displays this message 137 | --log 138 | log treshold (7 record everything, 0 record only emergency.) 139 | Defaults to %s 140 | --delay 141 | the number of seconds between two runs. 142 | Defaults to %s""" % (modconfig.LOG_TRESHOLD, modconfig.DELAY)) 143 | 144 | def handle_option(modconfig, opt_name, opt_value, help_meth): 145 | if opt_name in ('-h','--help'): 146 | help_meth() 147 | sys.exit(0) 148 | elif opt_name in ('-l','--log'): 149 | modconfig.LOG_TRESHOLD = int(opt_value) 150 | elif opt_name in ('-d', '--delay'): 151 | modconfig.DELAY = int(opt_value) 152 | elif opt_name in ('-n', '--no-detach'): 153 | modconfig.NODETACH = 1 154 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/date.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2006 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | 17 | """date manipulation helper functions""" 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import range 25 | from builtins import * 26 | 27 | import math 28 | 29 | try: 30 | from mx.DateTime import RelativeDateTime, strptime, Date 31 | STEP = 1 32 | except ImportError: 33 | from warnings import warn 34 | warn("mxDateTime not found, holiday management won't be available") 35 | from datetime import timedelta 36 | STEP = timedelta(days=1) 37 | else: 38 | endOfMonth = RelativeDateTime(months=1, day=-1) 39 | 40 | FRENCH_FIXED_HOLIDAYS = { 41 | 'jour_an' : '%s-01-01', 42 | 'fete_travail' : '%s-05-01', 43 | 'armistice1945' : '%s-05-08', 44 | 'fete_nat' : '%s-07-14', 45 | 'assomption' : '%s-08-15', 46 | 'toussaint' : '%s-11-01', 47 | 'armistice1918' : '%s-11-11', 48 | 'noel' : '%s-12-25', 49 | } 50 | 51 | 52 | FRENCH_MOBILE_HOLIDAYS = { 53 | 'paques2004' : '2004-04-12', 54 | 'ascension2004' : '2004-05-20', 55 | 'pentecote2004' : '2004-05-31', 56 | 57 | 'paques2005' : '2005-03-28', 58 | 'ascension2005' : '2005-05-05', 59 | 'pentecote2005' : '2005-05-16', 60 | 61 | 'paques2006' : '2006-04-17', 62 | 'ascension2006' : '2006-05-25', 63 | 'pentecote2006' : '2006-06-05', 64 | 65 | 'paques2007' : '2007-04-09', 66 | 'ascension2007' : '2007-05-17', 67 | 'pentecote2007' : '2007-05-28', 68 | 69 | 'paques2008' : '2008-03-24', 70 | 'ascension2008' : '2008-05-01', 71 | 'pentecote2008' : '2008-05-12', 72 | } 73 | 74 | def get_national_holidays(begin, end): 75 | """return french national days off between begin and end""" 76 | begin = Date(begin.year, begin.month, begin.day) 77 | end = Date(end.year, end.month, end.day) 78 | holidays = [strptime(datestr, '%Y-%m-%d') 79 | for datestr in list(FRENCH_MOBILE_HOLIDAYS.values())] 80 | for year in range(begin.year, end.year+1): 81 | for datestr in list(FRENCH_FIXED_HOLIDAYS.values()): 82 | date = strptime(datestr % year, '%Y-%m-%d') 83 | if date not in holidays: 84 | holidays.append(date) 85 | return [day for day in holidays if begin <= day < end] 86 | 87 | 88 | def add_days_worked(start, days): 89 | """adds date but try to only take days worked into account""" 90 | weeks, plus = divmod(days, 5) 91 | end = start+(weeks * 7) + plus 92 | if end.day_of_week >= 5: # saturday or sunday 93 | end += 2 94 | end += len([x for x in get_national_holidays(start, end+1) 95 | if x.day_of_week < 5]) 96 | if end.day_of_week >= 5: # saturday or sunday 97 | end += 2 98 | return end 99 | 100 | def nb_open_days(start, end): 101 | assert start <= end 102 | days = int(math.ceil((end - start).days)) 103 | weeks, plus = divmod(days, 7) 104 | if start.day_of_week > end.day_of_week: 105 | plus -= 2 106 | elif end.day_of_week == 6: 107 | plus -= 1 108 | open_days = weeks * 5 + plus 109 | nb_week_holidays = len([x for x in get_national_holidays(start, end+1) 110 | if x.day_of_week < 5 and x < end]) 111 | return open_days - nb_week_holidays 112 | 113 | 114 | def date_range(begin, end, step=STEP): 115 | """ 116 | enumerate dates between begin and end dates. 117 | 118 | step can either be oneDay, oneHour, oneMinute, oneSecond, oneWeek 119 | use endOfMonth to enumerate months 120 | """ 121 | date = begin 122 | while date < end : 123 | yield date 124 | date += step 125 | 126 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/debugger.py: -------------------------------------------------------------------------------- 1 | """customized version of pdb's default debugger. 2 | 3 | - sets up a history file 4 | - uses ipython if available to colorize lines of code 5 | - overrides list command to search for current block instead 6 | of using 5 lines of context 7 | """ 8 | from __future__ import print_function 9 | from __future__ import unicode_literals 10 | from __future__ import division 11 | from __future__ import absolute_import 12 | from future import standard_library 13 | standard_library.install_aliases() 14 | from builtins import * 15 | 16 | try: 17 | import readline 18 | except ImportError: 19 | readline = None 20 | import os 21 | import os.path as osp 22 | import sys 23 | from pdb import Pdb 24 | from io import StringIO 25 | import inspect 26 | 27 | try: 28 | from IPython import PyColorize 29 | except ImportError: 30 | def colorize(source, *args): 31 | """fallback colorize function""" 32 | return source 33 | else: 34 | def colorize(source, start_lineno, curlineno): 35 | """""" 36 | parser = PyColorize.Parser() 37 | output = StringIO() 38 | parser.format(source, output) 39 | annotated = [] 40 | for index, line in enumerate(output.getvalue().splitlines()): 41 | lineno = index + start_lineno 42 | if lineno == curlineno: 43 | annotated.append('%4s\t->\t%s' % (lineno, line)) 44 | else: 45 | annotated.append('%4s\t\t%s' % (lineno, line)) 46 | return '\n'.join(annotated) 47 | 48 | def getsource(obj): 49 | """Return the text of the source code for an object. 50 | 51 | The argument may be a module, class, method, function, traceback, frame, 52 | or code object. The source code is returned as a single string. An 53 | IOError is raised if the source code cannot be retrieved.""" 54 | lines, lnum = inspect.getsourcelines(obj) 55 | return ''.join(lines), lnum 56 | 57 | 58 | ################################################################ 59 | class Debugger(Pdb): 60 | """custom debugger 61 | 62 | - sets up a history file 63 | - uses ipython if available to colorize lines of code 64 | - overrides list command to search for current block instead 65 | of using 5 lines of context 66 | """ 67 | def __init__(self, tcbk): 68 | Pdb.__init__(self) 69 | self.reset() 70 | while tcbk.tb_next is not None: 71 | tcbk = tcbk.tb_next 72 | self._tcbk = tcbk 73 | self._histfile = osp.join(os.environ["HOME"], ".pdbhist") 74 | 75 | def setup_history_file(self): 76 | """if readline is available, read pdb history file 77 | """ 78 | if readline is not None: 79 | try: 80 | readline.read_history_file(self._histfile) 81 | except IOError: 82 | pass 83 | 84 | def start(self): 85 | """starts the interactive mode""" 86 | self.interaction(self._tcbk.tb_frame, self._tcbk) 87 | 88 | def setup(self, frame, tcbk): 89 | """setup hook: set up history file""" 90 | self.setup_history_file() 91 | Pdb.setup(self, frame, tcbk) 92 | 93 | def set_quit(self): 94 | """quit hook: save commands in the history file""" 95 | if readline is not None: 96 | readline.write_history_file(self._histfile) 97 | Pdb.set_quit(self) 98 | 99 | def complete_p(self, text, line, begin_idx, end_idx): 100 | """provide variable names completion for the ``p`` command""" 101 | namespace = dict(self.curframe.f_globals) 102 | namespace.update(self.curframe.f_locals) 103 | if '.' in text: 104 | return self.attr_matches(text, namespace) 105 | return [varname for varname in namespace if varname.startswith(text)] 106 | 107 | 108 | def attr_matches(self, text, namespace): 109 | """implementation coming from rlcompleter.Completer.attr_matches 110 | Compute matches when text contains a dot. 111 | 112 | Assuming the text is of the form NAME.NAME....[NAME], and is 113 | evaluatable in self.namespace, it will be evaluated and its attributes 114 | (as revealed by dir()) are used as possible completions. (For class 115 | instances, class members are also considered.) 116 | 117 | WARNING: this can still invoke arbitrary C code, if an object 118 | with a __getattr__ hook is evaluated. 119 | 120 | """ 121 | import re 122 | m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) 123 | if not m: 124 | return 125 | expr, attr = m.group(1, 3) 126 | object = eval(expr, namespace) 127 | words = dir(object) 128 | if hasattr(object,'__class__'): 129 | words.append('__class__') 130 | words = words + self.get_class_members(object.__class__) 131 | matches = [] 132 | n = len(attr) 133 | for word in words: 134 | if word[:n] == attr and word != "__builtins__": 135 | matches.append("%s.%s" % (expr, word)) 136 | return matches 137 | 138 | def get_class_members(self, klass): 139 | """implementation coming from rlcompleter.get_class_members""" 140 | ret = dir(klass) 141 | if hasattr(klass,'__bases__'): 142 | for base in klass.__bases__: 143 | ret = ret + self.get_class_members(base) 144 | return ret 145 | 146 | ## specific / overidden commands 147 | def do_list(self, arg): 148 | """overrides default list command to display the surrounding block 149 | instead of 5 lines of context 150 | """ 151 | self.lastcmd = 'list' 152 | if not arg: 153 | try: 154 | source, start_lineno = getsource(self.curframe) 155 | print(colorize(''.join(source), start_lineno, 156 | self.curframe.f_lineno)) 157 | except KeyboardInterrupt: 158 | pass 159 | except IOError: 160 | Pdb.do_list(self, arg) 161 | else: 162 | Pdb.do_list(self, arg) 163 | do_l = do_list 164 | 165 | def do_open(self, arg): 166 | """opens source file corresponding to the current stack level""" 167 | filename = self.curframe.f_code.co_filename 168 | lineno = self.curframe.f_lineno 169 | cmd = 'emacsclient --no-wait +%s %s' % (lineno, filename) 170 | os.system(cmd) 171 | 172 | do_o = do_open 173 | 174 | 175 | def pm(): 176 | """use our custom debugger""" 177 | dbg = Debugger(sys.last_traceback) 178 | dbg.start() 179 | 180 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/decorators.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """this module contains some function/method decorators 14 | 15 | :author: Logilab 16 | :copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE) 17 | :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org 18 | """ 19 | from __future__ import print_function 20 | from __future__ import unicode_literals 21 | from __future__ import division 22 | from __future__ import absolute_import 23 | from future import standard_library 24 | standard_library.install_aliases() 25 | from builtins import * 26 | from builtins import object 27 | __docformat__ = "restructuredtext en" 28 | 29 | # XXX rewrite so we can use the decorator syntax when keyarg has to be specified 30 | 31 | def cached(callableobj, keyarg=None): 32 | """simple decorator to cache result of method call""" 33 | #print callableobj, keyarg, callableobj.func_code.co_argcount 34 | if callableobj.__code__.co_argcount == 1 or keyarg == 0: 35 | 36 | def cache_wrapper1(self, *args): 37 | cache = '_%s_cache_' % callableobj.__name__ 38 | #print 'cache1?', cache 39 | try: 40 | return self.__dict__[cache] 41 | except KeyError: 42 | #print 'miss' 43 | value = callableobj(self, *args) 44 | setattr(self, cache, value) 45 | return value 46 | return cache_wrapper1 47 | 48 | elif keyarg: 49 | 50 | def cache_wrapper2(self, *args, **kwargs): 51 | cache = '_%s_cache_' % callableobj.__name__ 52 | key = args[keyarg-1] 53 | #print 'cache2?', cache, self, key 54 | try: 55 | _cache = self.__dict__[cache] 56 | except KeyError: 57 | #print 'init' 58 | _cache = {} 59 | setattr(self, cache, _cache) 60 | try: 61 | return _cache[key] 62 | except KeyError: 63 | #print 'miss', self, cache, key 64 | _cache[key] = callableobj(self, *args, **kwargs) 65 | return _cache[key] 66 | return cache_wrapper2 67 | 68 | def cache_wrapper3(self, *args): 69 | cache = '_%s_cache_' % callableobj.__name__ 70 | #print 'cache3?', cache, self, args 71 | try: 72 | _cache = self.__dict__[cache] 73 | except KeyError: 74 | #print 'init' 75 | _cache = {} 76 | setattr(self, cache, _cache) 77 | try: 78 | return _cache[args] 79 | except KeyError: 80 | #print 'miss' 81 | _cache[args] = callableobj(self, *args) 82 | return _cache[args] 83 | return cache_wrapper3 84 | 85 | def clear_cache(obj, funcname): 86 | """function to clear a cache handled by the cached decorator""" 87 | try: 88 | del obj.__dict__['_%s_cache_' % funcname] 89 | except KeyError: 90 | pass 91 | 92 | def copy_cache(obj, funcname, cacheobj): 93 | """copy cache for from cacheobj to obj""" 94 | cache = '_%s_cache_' % funcname 95 | try: 96 | setattr(obj, cache, cacheobj.__dict__[cache]) 97 | except KeyError: 98 | pass 99 | 100 | 101 | class wproperty(object): 102 | """simple descriptor expecting to take a modifier function as first argument 103 | and looking for a _ to retrieve the attribute 104 | """ 105 | def __init__(self, setfunc): 106 | self.setfunc = setfunc 107 | self.attrname = '_%s' % setfunc.__name__ 108 | 109 | def __set__(self, obj, value): 110 | self.setfunc(obj, value) 111 | 112 | def __get__(self, obj, cls): 113 | assert obj is not None 114 | return getattr(obj, self.attrname) 115 | 116 | 117 | class classproperty(object): 118 | def __init__(self, get): 119 | self.get = get 120 | def __get__(self, inst, cls): 121 | return self.get(cls) 122 | 123 | from time import clock 124 | def timed(f): 125 | def wrap(*args, **kwargs): 126 | t = clock() 127 | #for i in range(100): 128 | res = f(*args, **kwargs) 129 | print('%s time: %.9f' % (f.__name__, clock() - t)) 130 | return res 131 | return wrap 132 | 133 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/deprecation.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """Deprecation utilities 14 | 15 | :author: Logilab 16 | :copyright: 2006-2008 LOGILAB S.A. (Paris, FRANCE) 17 | :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org 18 | """ 19 | from __future__ import print_function 20 | from __future__ import unicode_literals 21 | from __future__ import division 22 | from __future__ import absolute_import 23 | from future import standard_library 24 | standard_library.install_aliases() 25 | from builtins import * 26 | __docformat__ = "restructuredtext en" 27 | 28 | import sys 29 | from warnings import warn 30 | 31 | from clonedigger.logilab.common.modutils import LazyObject, load_module_from_name 32 | 33 | 34 | class deprecated(type): 35 | """metaclass to print a warning on instantiation of a deprecated class""" 36 | 37 | def __call__(cls, *args, **kwargs): 38 | msg = getattr(cls, "__deprecation_warning__", 39 | "%s is deprecated" % cls.__name__) 40 | warn(msg, DeprecationWarning, stacklevel=2) 41 | return type.__call__(cls, *args, **kwargs) 42 | 43 | 44 | def class_renamed(old_name, new_class, message=None): 45 | """automatically creates a class which fires a DeprecationWarning 46 | when instantiated. 47 | 48 | >>> Set = class_renamed('Set', set, 'Set is now replaced by set') 49 | >>> s = Set() 50 | sample.py:57: DeprecationWarning: Set is now replaced by set 51 | s = Set() 52 | >>> 53 | """ 54 | clsdict = {} 55 | if message is None: 56 | message = '%s is deprecated' % old_name 57 | clsdict['__deprecation_warning__'] = message 58 | try: 59 | # new-style class 60 | return deprecated(old_name, (new_class,), clsdict) 61 | except (NameError, TypeError): 62 | # old-style class 63 | class DeprecatedClass(new_class): 64 | """FIXME: There might be a better way to handle old/new-style class 65 | """ 66 | def __init__(self, *args, **kwargs): 67 | warn(message, DeprecationWarning, stacklevel=2) 68 | new_class.__init__(self, *args, **kwargs) 69 | return DeprecatedClass 70 | 71 | 72 | def class_moved(new_class, old_name=None, message=None): 73 | """nice wrapper around class_renamed when a class has been moved into 74 | another module 75 | """ 76 | if old_name is None: 77 | old_name = new_class.__name__ 78 | if message is None: 79 | message = 'class %s is now available as %s.%s' % ( 80 | old_name, new_class.__module__, new_class.__name__) 81 | return class_renamed(old_name, new_class, message) 82 | 83 | 84 | def deprecated_function(new_func, message=None): 85 | """creates a function which fires a DeprecationWarning when used 86 | 87 | For example, if is deprecated in favour of : 88 | >>> bar = deprecated_function(foo, 'bar is deprecated') 89 | >>> bar() 90 | sample.py:57: DeprecationWarning: bar is deprecated 91 | bar() 92 | >>> 93 | """ 94 | if message is None: 95 | message = "this function is deprecated, use %s instead" % ( 96 | new_func.__name__) 97 | def deprecated(*args, **kwargs): 98 | warn(message, DeprecationWarning, stacklevel=2) 99 | return new_func(*args, **kwargs) 100 | return deprecated 101 | 102 | 103 | def moved(modpath, objname): 104 | """use to tell that a callable has been moved to a new module. 105 | 106 | It returns a callable wrapper, so that when its called a warning is printed 107 | telling where the object can be found, import is done (and not before) and 108 | the actual object is called. 109 | 110 | NOTE: the usage is somewhat limited on classes since it will fail if the 111 | wrapper is use in a class ancestors list, use the `class_moved` function 112 | instead (which has no lazy import feature though). 113 | """ 114 | def callnew(*args, **kwargs): 115 | message = "object %s has been moved to module %s" % (objname, modpath) 116 | warn(message, DeprecationWarning, stacklevel=2) 117 | m = load_module_from_name(modpath) 118 | return getattr(m, objname)(*args, **kwargs) 119 | return callnew 120 | 121 | 122 | class WarnLazyObject(LazyObject): 123 | def __init__(self, oldname, newname): 124 | # XXX doesn't work if module isn't in a package 125 | package, module = newname.rsplit('.', 1) 126 | super(WarnLazyObject, self).__init__(package, module) 127 | self.oldname = oldname 128 | self.newname = newname 129 | print('hop', oldname, newname) 130 | sys.modules[oldname] = self 131 | 132 | def __getobj(self): 133 | if self._imported is None: 134 | message = "module %s has moved, it's now %s" % ( 135 | self.oldname, self.newname) 136 | warn(message, DeprecationWarning, stacklevel=2) 137 | return super(WarnLazyObject, self).__getobj() 138 | 139 | module_moved = WarnLazyObject 140 | 141 | def obsolete(reason="This function is obsolete"): 142 | """this function is an alternative to `deprecated_function` 143 | when there's no real replacement for the deprecated function 144 | """ 145 | def newdecorator(func): 146 | def wrapped(*args, **kwargs): 147 | warn(reason, DeprecationWarning, stacklevel=2) 148 | return func(*args, **kwargs) 149 | return wrapped 150 | return newdecorator 151 | 152 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/graph.py: -------------------------------------------------------------------------------- 1 | """some various graph manipuliation utilities 2 | 3 | (dot generation adapted from pypy/translator/tool/make_dot.py) 4 | 5 | :organization: Logilab 6 | :copyright: 2003-2007 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 7 | :contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr 8 | """ 9 | from __future__ import unicode_literals 10 | from __future__ import print_function 11 | from __future__ import division 12 | from __future__ import absolute_import 13 | from future import standard_library 14 | standard_library.install_aliases() 15 | from builtins import range 16 | from builtins import * 17 | from builtins import object 18 | 19 | __docformat__ = "restructuredtext en" 20 | __metaclass__ = type 21 | 22 | import os.path as osp 23 | import os 24 | 25 | def escape(value): 26 | """make usable in a dot file""" 27 | lines = [line.replace('"', '\\"') for line in value.split('\n')] 28 | data = '\\l'.join(lines) 29 | return '\\n' + data 30 | 31 | def target_info_from_filename(filename): 32 | """transforms /some/path/foo.png into ('/some/path', 'foo.png', 'png')""" 33 | abspath = osp.abspath(filename) 34 | basename = osp.basename(filename) 35 | storedir = osp.dirname(abspath) 36 | target = filename.split('.')[-1] 37 | return storedir, basename, target 38 | 39 | 40 | class DotBackend(object): 41 | """Dot File backend""" 42 | def __init__(self, graphname, rankdir=None, size=None, ratio=None, charset='utf-8'): 43 | self.graphname = graphname 44 | self.lines = [] 45 | self._source = None 46 | self.emit("digraph %s {" % normalize_node_id(graphname)) 47 | if rankdir: 48 | self.emit('rankdir=%s' % rankdir) 49 | if ratio: 50 | self.emit('ratio=%s' % ratio) 51 | if size: 52 | self.emit('size="%s"' % size) 53 | if charset: 54 | assert charset.lower() in ('utf-8', 'iso-8859-1', 'latin1'), \ 55 | 'unsupported charset %s' % charset 56 | self.emit('charset="%s"' % charset) 57 | 58 | def get_source(self): 59 | """returns self._source""" 60 | if self._source is None: 61 | self.emit("}") 62 | self._source = '\n'.join(self.lines) 63 | del self.lines 64 | return self._source 65 | 66 | source = property(get_source) 67 | 68 | def generate(self, outputfile=None, dotfile=None): 69 | """generates a graph file 70 | :param target: output format ('png', 'ps', etc.). If None, 71 | the raw dot source will be returned 72 | :return: a path to the generated file 73 | """ 74 | if outputfile is not None: 75 | storedir, basename, target = target_info_from_filename(outputfile) 76 | else: 77 | storedir = '/tmp' 78 | basename = '%s.png' % (self.graphname) 79 | target = 'png' 80 | outputfile = osp.join(storedir, basename) 81 | dotfile = dotfile or ('%s.dot' % self.graphname) 82 | dot_sourcepath = osp.join(storedir, dotfile) 83 | pdot = file(dot_sourcepath, 'w') 84 | if isinstance(self.source, str): 85 | pdot.write(self.source.encode('UTF8')) 86 | else: 87 | pdot.write(self.source) 88 | pdot.close() 89 | if target != 'dot': 90 | os.system('dot -T%s %s -o%s' % (target, dot_sourcepath, outputfile)) 91 | os.unlink(dot_sourcepath) 92 | return outputfile 93 | 94 | def emit(self, line): 95 | """adds to final output""" 96 | self.lines.append(line) 97 | 98 | def emit_edge(self, name1, name2, **props): 99 | """emits edge from to 100 | 101 | authorized props: see http://www.graphviz.org/doc/info/attrs.html 102 | """ 103 | attrs = ['%s="%s"' % (prop, value) for prop, value in list(props.items())] 104 | self.emit('edge [%s];' % ", ".join(attrs)) 105 | self.emit('%s -> %s' % (normalize_node_id(name1), normalize_node_id(name2))) 106 | 107 | def emit_node(self, name, **props): 108 | """authorized props: see http://www.graphviz.org/doc/info/attrs.html 109 | """ 110 | attrs = ['%s="%s"' % (prop, value) for prop, value in list(props.items())] 111 | self.emit('%s [%s];' % (normalize_node_id(name), ", ".join(attrs))) 112 | 113 | def normalize_node_id(nid): 114 | """returns a suitable DOT node id for `nid`""" 115 | return '"%s"' % nid 116 | 117 | class GraphGenerator(object): 118 | def __init__(self, backend): 119 | # the backend is responsible to output the graph is a particular format 120 | self.backend = backend 121 | 122 | def generate(self, visitor, propshdlr, outputfile=None): 123 | # the visitor 124 | # the properties handler is used to get nodes and edges properties 125 | # according to the graph and to the backend 126 | self.propshdlr = propshdlr 127 | for nodeid, node in visitor.nodes(): 128 | props = propshdlr.node_properties(node) 129 | self.backend.emit_node(nodeid, **props) 130 | for subjnode, objnode, edge in visitor.edges(): 131 | props = propshdlr.edge_properties(edge, subjnode, objnode) 132 | self.backend.emit_edge(subjnode, objnode, **props) 133 | return self.backend.generate(outputfile) 134 | 135 | 136 | 137 | def get_cycles(graph_dict, vertices=None): 138 | '''given a dictionnary representing an ordered graph (i.e. key are vertices 139 | and values is a list of destination vertices representing edges), return a 140 | list of detected cycles 141 | ''' 142 | if not graph_dict: 143 | return () 144 | result = [] 145 | if vertices is None: 146 | vertices = list(graph_dict.keys()) 147 | for vertice in vertices: 148 | _get_cycles(graph_dict, vertice, [], result) 149 | return result 150 | 151 | def _get_cycles(graph_dict, vertice=None, path=None, result=None): 152 | """recursive function doing the real work for get_cycles""" 153 | if vertice in path: 154 | cycle = [vertice] 155 | for i in range(len(path)-1, 0, -1): 156 | node = path[i] 157 | if node == vertice: 158 | break 159 | cycle.insert(0, node) 160 | # make a canonical representation 161 | start_from = min(cycle) 162 | index = cycle.index(start_from) 163 | cycle = cycle[index:] + cycle[0:index] 164 | # append it to result if not already in 165 | if not cycle in result: 166 | result.append(cycle) 167 | return 168 | path.append(vertice) 169 | try: 170 | for node in graph_dict[vertice]: 171 | _get_cycles(graph_dict, node, path, result) 172 | except KeyError: 173 | pass 174 | path.pop() 175 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/html.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2002-2006 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | """ 16 | from __future__ import unicode_literals 17 | from __future__ import print_function 18 | from __future__ import division 19 | from __future__ import absolute_import 20 | from future import standard_library 21 | standard_library.install_aliases() 22 | from builtins import str 23 | from builtins import * 24 | 25 | from warnings import warn 26 | warn('html module is deprecated and will disappear in a near release', 27 | DeprecationWarning, stacklevel=2) 28 | 29 | __revision__ = "$Id: html.py,v 1.5 2003-09-12 11:54:47 syt Exp $" 30 | 31 | import traceback 32 | from xml.sax.saxutils import escape 33 | 34 | # mk html traceback error ##################################################### 35 | 36 | def html_traceback(info, exception, 37 | title='', encoding='ISO-8859-1', body=''): 38 | """ return an html formatted traceback from python exception infos. 39 | """ 40 | #typ, value, tbck = info 41 | stacktb = traceback.extract_tb(info[2]) #tbck) 42 | strings = [] 43 | if body: 44 | strings.append('
') 45 | strings.append(body) 46 | strings.append('
') 47 | if title: 48 | strings.append('

%s

'% escape(title)) 49 | strings.append('

%s

' % escape(str(exception))) 50 | strings.append('
') 51 | for stackentry in stacktb : 52 | strings.append('File %s, line ' 53 | '%s, function ' 54 | '%s:
'%( 55 | escape(stackentry[0]), stackentry[1], stackentry[2])) 56 | if stackentry[3]: 57 | string = escape(repr(stackentry[3])[1:-1])#.encode(encoding) 58 | strings.append('  %s
\n' % string) 59 | strings.append('
') 60 | return '\n'.join(strings) 61 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/interface.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2002-2007 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """ 17 | bases class for interfaces to provide "light" interface handling. 18 | 19 | TODO: 20 | _ implements a check method which check that an object implements the 21 | interface 22 | _ Attribute objects 23 | 24 | This module requires at least python 2.2 25 | """ 26 | from __future__ import unicode_literals 27 | from __future__ import print_function 28 | from __future__ import division 29 | from __future__ import absolute_import 30 | from future import standard_library 31 | standard_library.install_aliases() 32 | from builtins import * 33 | from builtins import object 34 | 35 | from types import ListType, TupleType 36 | 37 | class Interface(object): 38 | """base class for interfaces""" 39 | def is_implemented_by(cls, instance): 40 | return implements(instance, cls) 41 | is_implemented_by = classmethod(is_implemented_by) 42 | 43 | 44 | def implements(obj, interface): 45 | """return true if the give object (maybe an instance or class) implements 46 | the interface 47 | """ 48 | kimplements = getattr(obj, '__implements__', ()) 49 | if not isinstance(kimplements, (list, tuple)): 50 | kimplements = (kimplements,) 51 | for implementedinterface in kimplements: 52 | if issubclass(implementedinterface, interface): 53 | return True 54 | return False 55 | 56 | 57 | def extend(klass, interface, _recurs=False): 58 | """add interface to klass'__implements__ if not already implemented in. 59 | 60 | if klass is subclassed, ensure subclasses __implements__ it as well. 61 | 62 | NOTE: klass should be e new class. 63 | """ 64 | if not implements(klass, interface): 65 | try: 66 | kimplements = klass.__implements__ 67 | kimplementsklass = type(kimplements) 68 | kimplements = list(kimplements) 69 | except AttributeError: 70 | kimplementsklass = tuple 71 | kimplements = [] 72 | kimplements.append(interface) 73 | klass.__implements__ = kimplementsklass(kimplements) 74 | for subklass in klass.__subclasses__(): 75 | extend(subklass, interface, _recurs=True) 76 | elif _recurs: 77 | for subklass in klass.__subclasses__(): 78 | extend(subklass, interface, _recurs=True) 79 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/logger.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2002-2003 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | 16 | Define a logger interface and two concrete loggers : one which prints 17 | everything on stdout, the other using syslog. 18 | """ 19 | from __future__ import unicode_literals 20 | from __future__ import print_function 21 | from __future__ import division 22 | from __future__ import absolute_import 23 | from future import standard_library 24 | standard_library.install_aliases() 25 | from builtins import str 26 | from builtins import * 27 | from builtins import object 28 | 29 | from warnings import warn 30 | warn('logger module is deprecated and will disappear in a future release. \ 31 | use logging module instead.', 32 | DeprecationWarning, stacklevel=1) 33 | 34 | __revision__ = "$Id: logger.py,v 1.18 2006-02-03 14:17:42 adim Exp $" 35 | 36 | 37 | import sys 38 | import traceback 39 | import time 40 | 41 | 42 | LOG_EMERG = 0 43 | LOG_ALERT = 1 44 | LOG_CRIT = 2 45 | LOG_ERR = 3 46 | LOG_WARN = 4 47 | LOG_NOTICE = 5 48 | LOG_INFO = 6 49 | LOG_DEBUG = 7 50 | 51 | INDICATORS = ['emergency', 'alert', 'critical', 'error', 52 | 'warning', 'notice', 'info', 'debug'] 53 | 54 | 55 | def make_logger(method='print', threshold=LOG_DEBUG, sid=None, output=None): 56 | """return a logger for the given method 57 | 58 | known methods are 'print', 'eprint' and syslog' 59 | """ 60 | if method == 'print': 61 | if output is None: 62 | output = sys.stdout 63 | return PrintLogger(threshold, output, sid=sid) 64 | elif method == 'eprint': 65 | return PrintLogger(threshold, sys.stderr, sid=sid) 66 | elif method == 'syslog': 67 | return SysLogger(threshold, sid) 68 | elif method == 'file': 69 | if not output: 70 | raise ValueError('No logfile specified') 71 | else: 72 | logfile = open(output, 'a') 73 | return PrintLogger(threshold, logfile, sid=sid) 74 | else: 75 | raise ValueError('Unknown logger method: %r' % method) 76 | 77 | 78 | class AbstractLogger(object): 79 | """logger interface. 80 | Priorities allow to filter on the importance of events 81 | An event gets logged if it's priority is lower than the threshold""" 82 | 83 | def __init__(self, threshold=LOG_DEBUG, priority_indicator=1): 84 | self.threshold = threshold 85 | self.priority_indicator = priority_indicator 86 | 87 | def log(self, priority=LOG_DEBUG, message='', substs=None): 88 | """log a message with priority 89 | substs are optional substrings 90 | """ 91 | #print 'LOG', self, priority, self.threshold, message 92 | if priority <= self.threshold : 93 | if substs is not None: 94 | message = message % substs 95 | if self.priority_indicator: 96 | message = '[%s] %s' % (INDICATORS[priority], message) 97 | self._writelog(priority, message) 98 | 99 | def _writelog(self, priority, message): 100 | """Override this method in concrete class """ 101 | raise NotImplementedError() 102 | 103 | def log_traceback(self, priority=LOG_ERR, tb_info=None): 104 | """log traceback information with priority 105 | """ 106 | assert tb_info is not None 107 | e_type, value, tbck = tb_info 108 | stacktb = traceback.extract_tb(tbck) 109 | l = ['Traceback (most recent call last):'] 110 | for stackentry in stacktb : 111 | if stackentry[3]: 112 | plus = '\n %s' % stackentry[3] 113 | else: 114 | plus = '' 115 | l.append('filename="%s" line_number="%s" function_name="%s"%s' % 116 | (stackentry[0], stackentry[1], stackentry[2], plus)) 117 | try: 118 | l.append(str(e_type) + ': ' + value.__str__()) 119 | except UnicodeError: 120 | l.append(str(e_type) + ' (message can\'t be displayed)') 121 | 122 | self.log(priority, '\n'.join(l)) 123 | 124 | 125 | class PrintLogger(AbstractLogger): 126 | """logger implementation 127 | 128 | log everything to a file, using the standard output by default 129 | """ 130 | 131 | def __init__(self, threshold, output=sys.stdout, sid=None, 132 | encoding='UTF-8'): 133 | AbstractLogger.__init__(self, threshold) 134 | self.output = output 135 | self.sid = sid 136 | self.encoding = encoding 137 | 138 | def _writelog(self, priority, message): 139 | """overridden from AbstractLogger""" 140 | if isinstance(message, str): 141 | message = message.encode(self.encoding, 'replace') 142 | if self.sid is not None: 143 | self.output.write('[%s] [%s] %s\n' % (time.asctime(), self.sid, 144 | message)) 145 | else: 146 | self.output.write('[%s] %s\n' % (time.asctime(), message)) 147 | self.output.flush() 148 | 149 | class SysLogger(AbstractLogger): 150 | """ logger implementation 151 | 152 | log everything to syslog daemon 153 | use the LOCAL_7 facility 154 | """ 155 | 156 | def __init__(self, threshold, sid=None, encoding='UTF-8'): 157 | import syslog 158 | AbstractLogger.__init__(self, threshold) 159 | if sid is None: 160 | sid = 'syslog' 161 | self.encoding = encoding 162 | syslog.openlog(sid, syslog.LOG_PID) 163 | 164 | def _writelog(self, priority, message): 165 | """overridden from AbstractLogger""" 166 | import syslog 167 | if isinstance(message, str): 168 | message = message.encode(self.encoding, 'replace') 169 | syslog.syslog(priority | syslog.LOG_LOCAL7, message) 170 | 171 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/logging_ext.py: -------------------------------------------------------------------------------- 1 | # -*- coding: iso-8859-1 -*- 2 | # Copyright (c) 2007 LOGILAB S.A. (Paris, FRANCE). 3 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 4 | # 5 | # This program is free software; you can redistribute it and/or modify 6 | # it under the terms of the GNU General Public License as published by 7 | # the Free Software Foundation; either version 2 of the License, or 8 | # (at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program; if not, write to the Free Software Foundation, Inc., 16 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | """ Copyright (c) 2007 LOGILAB S.A. (Paris, FRANCE). 18 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 19 | 20 | This module provides extensions to the logging module from the standard library. 21 | """ 22 | from __future__ import unicode_literals 23 | from __future__ import print_function 24 | from __future__ import division 25 | from __future__ import absolute_import 26 | from future import standard_library 27 | standard_library.install_aliases() 28 | from builtins import * 29 | 30 | import logging 31 | 32 | from clonedigger.logilab.common.textutils import colorize_ansi 33 | 34 | def xxx_cyan(record): 35 | if 'XXX' in record.message: 36 | return 'cyan' 37 | 38 | class ColorFormatter(logging.Formatter): 39 | """ 40 | A color Formatter for the logging standard module. 41 | 42 | By default, colorize CRITICAL and ERROR in red, WARNING in orange 43 | and INFO in yellow. 44 | 45 | self.colors is customizable via the 'color' constructor argument (dictionnary). 46 | 47 | self.colorfilters is a list of functions that get the LogRecord 48 | and return a color name or None. 49 | """ 50 | 51 | def __init__(self, fmt=None, datefmt=None, colors=None): 52 | logging.Formatter.__init__(self, fmt, datefmt) 53 | self.colorfilters = [] 54 | self.colors = {'CRITICAL': 'red', 55 | 'ERROR': 'red', 56 | 'WARNING': 'magenta', 57 | 'INFO': 'yellow', 58 | } 59 | if colors is not None: 60 | assert isinstance(colors, dict) 61 | self.colors.update(colors) 62 | 63 | def format(self, record): 64 | msg = logging.Formatter.format(self, record) 65 | if record.levelname in self.colors: 66 | color = self.colors[record.levelname] 67 | return colorize_ansi(msg, color) 68 | else: 69 | for cf in self.colorfilters: 70 | color = cf(record) 71 | if color: 72 | return colorize_ansi(msg, color) 73 | return msg 74 | 75 | def set_color_formatter(logger=None, **kw): 76 | """ 77 | Install a color formatter on the 'logger'. If not given, it will 78 | defaults to the default logger. 79 | 80 | Any additional keyword will be passed as-is to the ColorFormatter 81 | constructor. 82 | """ 83 | if logger is None: 84 | logger = logging.getLogger() 85 | if not logger.handlers: 86 | logging.basicConfig() 87 | format_msg = logger.handlers[0].formatter._fmt 88 | fmt = ColorFormatter(format_msg, **kw) 89 | fmt.colorfilters.append(xxx_cyan) 90 | logger.handlers[0].setFormatter(fmt) 91 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/logservice.py: -------------------------------------------------------------------------------- 1 | """log utilities 2 | 3 | Copyright (c) 2003-2004 LOGILAB S.A. (Paris, FRANCE), all rights reserved. 4 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 5 | """ 6 | from __future__ import unicode_literals 7 | from __future__ import print_function 8 | from __future__ import division 9 | from __future__ import absolute_import 10 | from future import standard_library 11 | standard_library.install_aliases() 12 | from builtins import * 13 | 14 | from warnings import warn 15 | warn('logservice module is deprecated and will disappear in a near release. \ 16 | use logging module instead.', 17 | DeprecationWarning, stacklevel=2) 18 | 19 | __revision__ = "$Id: logservice.py,v 1.5 2006-03-05 16:13:28 syt Exp $" 20 | 21 | from clonedigger.logilab.common.logger import make_logger, LOG_ERR, LOG_WARN, LOG_NOTICE, \ 22 | LOG_INFO, LOG_CRIT, LOG_DEBUG 23 | 24 | def init_log(treshold, method='eprint', sid='common-log-service', 25 | logger=None, output=None): 26 | """init the logging system and and log methods to builtins""" 27 | if logger is None: 28 | logger = make_logger(method, treshold, sid, output=output) 29 | # add log functions and constants to builtins 30 | __builtins__.update({'log': logger.log, 31 | 'log_traceback' : logger.log_traceback, 32 | 'LOG_CRIT': LOG_CRIT, 33 | 'LOG_ERR': LOG_ERR, 34 | 'LOG_WARN': LOG_WARN, 35 | 'LOG_NOTICE': LOG_NOTICE, 36 | 'LOG_INFO' : LOG_INFO, 37 | 'LOG_DEBUG': LOG_DEBUG, 38 | }) 39 | 40 | init_log(LOG_ERR) 41 | 42 | 43 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/monclient.py: -------------------------------------------------------------------------------- 1 | """Simple interpreter client for monserver 2 | provides a simple readline interface. 3 | """ 4 | from __future__ import print_function 5 | from __future__ import unicode_literals 6 | from __future__ import division 7 | from __future__ import absolute_import 8 | from future import standard_library 9 | standard_library.install_aliases() 10 | from builtins import input 11 | from builtins import * 12 | 13 | from warnings import warn 14 | warn('this module is deprecated and will disappear in a near release', 15 | DeprecationWarning, stacklevel=1) 16 | 17 | from socket import socket, SOCK_STREAM, AF_INET 18 | from select import select 19 | import sys 20 | import readline 21 | import threading 22 | 23 | class SocketPrinter(threading.Thread): 24 | """A thread that reads from a socket and output 25 | to stdout as data are received""" 26 | def __init__(self, sock): 27 | threading.Thread.__init__(self) 28 | self.socket = sock 29 | self.stop = False 30 | 31 | def run(self): 32 | """prints socket input indefinitely""" 33 | fd = self.socket.fileno() 34 | self.socket.setblocking(0) 35 | while not self.stop: 36 | iwl, _, _ = select([fd], [], [], 2) 37 | if fd in iwl: 38 | data = self.socket.recv(100) 39 | if data: 40 | sys.stdout.write(data) 41 | sys.stdout.flush() 42 | 43 | 44 | 45 | def client( host, port ): 46 | """simple client that just sends input to the server""" 47 | sock = socket( AF_INET, SOCK_STREAM ) 48 | sock.connect( (host, port) ) 49 | sp_thread = SocketPrinter(sock) 50 | sp_thread.start() 51 | while 1: 52 | try: 53 | line = input() + "\n" 54 | sock.send( line ) 55 | except EOFError: 56 | print("Bye") 57 | break 58 | except: 59 | sp_thread.stop = True 60 | sp_thread.join() 61 | raise 62 | sp_thread.stop = True 63 | sp_thread.join() 64 | 65 | 66 | if __name__ == "__main__": 67 | server_host = sys.argv[1] 68 | server_port = int(sys.argv[2]) 69 | client(server_host, server_port) 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/monserver.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/logilab/common/monserver.py -------------------------------------------------------------------------------- /clonedigger/logilab/common/optparser.py: -------------------------------------------------------------------------------- 1 | # -*- coding: iso-8859-15 -*- 2 | # Copyright (c) 2006 LOGILAB S.A. (Paris, FRANCE). 3 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 4 | # 5 | # This program is free software; you can redistribute it and/or modify it under 6 | # the terms of the GNU General Public License as published by the Free Software 7 | # Foundation; either version 2 of the License, or (at your option) any later 8 | # version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License along with 15 | # this program; if not, write to the Free Software Foundation, Inc., 16 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 | """Extend OptionParser with commands. 18 | 19 | Example: 20 | 21 | >>> parser = OptionParser() 22 | >>> parser.usage = '%prog COMMAND [options] ...' 23 | >>> parser.add_command('build', 'mymod.build') 24 | >>> parser.add_command('clean', run_clean, add_opt_clean) 25 | >>> run, options, args = parser.parse_command(sys.argv[1:]) 26 | >>> return run(options, args[1:]) 27 | 28 | With mymod.build that defines two functions run and add_options 29 | """ 30 | from __future__ import print_function 31 | from __future__ import unicode_literals 32 | from __future__ import division 33 | from __future__ import absolute_import 34 | from future import standard_library 35 | standard_library.install_aliases() 36 | from builtins import * 37 | 38 | # XXX merge with optik_ext ? merge with clcommands ? 39 | 40 | import sys 41 | import optparse 42 | 43 | class OptionParser(optparse.OptionParser): 44 | 45 | def __init__(self, *args, **kwargs): 46 | optparse.OptionParser.__init__(self, *args, **kwargs) 47 | self._commands = {} 48 | self.min_args, self.max_args = 0, 1 49 | 50 | def add_command(self, name, mod_or_funcs, help=''): 51 | """name of the command 52 | name of module or tuple of functions (run, add_options) 53 | """ 54 | assert isinstance(mod_or_funcs, str) or isinstance(mod_or_funcs, tuple), \ 55 | "mod_or_funcs has to be a module name or a tuple of functions" 56 | self._commands[name] = (mod_or_funcs, help) 57 | 58 | def print_main_help(self): 59 | optparse.OptionParser.print_help(self) 60 | print('\ncommands:') 61 | for cmdname, (_, help) in list(self._commands.items()): 62 | print('% 10s - %s' % (cmdname, help)) 63 | 64 | def parse_command(self, args): 65 | if len(args) == 0: 66 | self.print_main_help() 67 | sys.exit(1) 68 | cmd = args[0] 69 | args = args[1:] 70 | if cmd not in self._commands: 71 | if cmd in ('-h', '--help'): 72 | self.print_main_help() 73 | sys.exit(0) 74 | elif self.version is not None and cmd == "--version": 75 | self.print_version() 76 | sys.exit(0) 77 | self.error('unknow command') 78 | self.prog = '%s %s' % (self.prog, cmd) 79 | mod_or_f, help = self._commands[cmd] 80 | # optparse inserts self.description between usage and options help 81 | self.description = help 82 | if isinstance(mod_or_f, str): 83 | exec('from %s import run, add_options' % mod_or_f) 84 | else: 85 | run, add_options = mod_or_f 86 | add_options(self) 87 | (options, args) = self.parse_args(args) 88 | if not (self.min_args <= len(args) <= self.max_args): 89 | self.error('incorrect number of arguments') 90 | return run, options, args 91 | 92 | 93 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/pdf_ext.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify 2 | # it under the terms of the GNU General Public License as published by 3 | # the Free Software Foundation; either version 2 of the License, or 4 | # (at your option) any later version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2003-2007 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | 16 | manipulate pdf and fdf files. pdftk recommended. 17 | 18 | Notes regarding pdftk, pdf forms and fdf files (form definition file) 19 | fields names can be extracted with: 20 | pdftk orig.pdf generate_fdf output truc.fdf 21 | to merge fdf and pdf: 22 | pdftk orig.pdf fill_form test.fdf output result.pdf [flatten] 23 | without flatten, one could further edit the resulting form. 24 | with flatten, everything is turned into text. 25 | """ 26 | from __future__ import unicode_literals 27 | from __future__ import print_function 28 | from __future__ import division 29 | from __future__ import absolute_import 30 | from future import standard_library 31 | standard_library.install_aliases() 32 | from builtins import * 33 | # XXX seems very unix specific 34 | # TODO: check availability of pdftk at import 35 | 36 | 37 | import os 38 | 39 | HEAD="""%FDF-1.2 40 | %\xE2\xE3\xCF\xD3 41 | 1 0 obj 42 | << 43 | /FDF 44 | << 45 | /Fields [ 46 | """ 47 | 48 | TAIL="""] 49 | >> 50 | >> 51 | endobj 52 | trailer 53 | 54 | << 55 | /Root 1 0 R 56 | >> 57 | %%EOF 58 | """ 59 | 60 | def output_field( f ): 61 | return "\xfe\xff" + "".join( [ "\x00"+c for c in f ] ) 62 | 63 | def extract_keys(lines): 64 | keys = [] 65 | for line in lines: 66 | if line.startswith('/V'): 67 | pass #print 'value',line 68 | elif line.startswith('/T'): 69 | key = line[7:-2] 70 | key = ''.join(key.split('\x00')) 71 | keys.append( key ) 72 | return keys 73 | 74 | def write_field(out, key, value): 75 | out.write("<<\n") 76 | if value: 77 | out.write("/V (%s)\n" %value) 78 | else: 79 | out.write("/V /\n") 80 | out.write("/T (%s)\n" % output_field(key) ) 81 | out.write(">> \n") 82 | 83 | def write_fields(out, fields): 84 | out.write(HEAD) 85 | for (key,value,comment) in fields: 86 | write_field(out, key, value) 87 | write_field(out, key+"a", value) # pour copie-carbone sur autres pages 88 | out.write(TAIL) 89 | 90 | def extract_keys_from_pdf(filename): 91 | # what about using 'pdftk filename dump_data_fields' and parsing the output ? 92 | os.system('pdftk %s generate_fdf output /tmp/toto.fdf' % filename) 93 | lines = file('/tmp/toto.fdf').readlines() 94 | return extract_keys(lines) 95 | 96 | 97 | def fill_pdf(infile, outfile, fields): 98 | write_fields(file('/tmp/toto.fdf', 'w'), fields) 99 | os.system('pdftk %s fill_form /tmp/toto.fdf output %s flatten' % (infile, outfile)) 100 | 101 | def testfill_pdf(infile, outfile): 102 | keys = extract_keys_from_pdf(infile) 103 | fields = [] 104 | for key in keys: 105 | fields.append( (key, key, '') ) 106 | fill_pdf(infile, outfile, fields) 107 | 108 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/umessage.py: -------------------------------------------------------------------------------- 1 | """unicode email support""" 2 | from __future__ import unicode_literals 3 | from __future__ import print_function 4 | from __future__ import division 5 | from __future__ import absolute_import 6 | from future import standard_library 7 | standard_library.install_aliases() 8 | from builtins import str 9 | from builtins import * 10 | from builtins import object 11 | 12 | import email 13 | from email.Utils import parseaddr, parsedate 14 | from email.Header import decode_header 15 | 16 | try: 17 | from mx.DateTime import DateTime 18 | except ImportError: 19 | def DateTime(*args): return None 20 | 21 | def decode_QP(string): 22 | parts = [] 23 | for decoded, charset in decode_header(string): 24 | if charset is None: 25 | charset = 'iso-8859-15' 26 | parts.append(str(decoded, charset, 'replace')) 27 | 28 | return u' '.join(parts) 29 | 30 | def message_from_file(fd): 31 | try: 32 | return UMessage(email.message_from_file(fd)) 33 | except email.Errors.MessageParseError: 34 | return '' 35 | 36 | def message_from_string(string): 37 | try: 38 | return UMessage(email.message_from_string(string)) 39 | except email.Errors.MessageParseError: 40 | return '' 41 | 42 | class UMessage(object): 43 | """Encapsulates an email.Message instance and returns only unicode objects""" 44 | 45 | def __init__(self, message): 46 | self.message = message 47 | 48 | # email.Message interface ################################################# 49 | 50 | def get(self, header, default=None): 51 | value = self.message.get(header, default) 52 | if value: 53 | return decode_QP(value) 54 | return value 55 | 56 | def get_all(self, header, default=()): 57 | return [decode_QP(val) for val in self.message.get_all(header, default) 58 | if val is not None] 59 | 60 | def get_payload(self, index=None, decode=False): 61 | message = self.message 62 | if index is None: 63 | payload = message.get_payload(index, decode) 64 | if isinstance(payload, list): 65 | return [UMessage(msg) for msg in payload] 66 | if message.get_content_maintype() != 'text': 67 | return payload 68 | 69 | charset = message.get_content_charset() or 'iso-8859-1' 70 | if charset == 'unknown-8bit': 71 | charset = 'iso-8859-1' 72 | return str(payload or '', charset) 73 | else: 74 | payload = UMessage(message.get_payload(index, decode)) 75 | return payload 76 | 77 | def is_multipart(self): 78 | return self.message.is_multipart() 79 | 80 | def get_boundary(self): 81 | return self.message.get_boundary() 82 | 83 | def walk(self): 84 | for part in self.message.walk(): 85 | yield UMessage(part) 86 | 87 | def get_content_maintype(self): 88 | return str(self.message.get_content_maintype()) 89 | 90 | def get_content_type(self): 91 | return str(self.message.get_content_type()) 92 | 93 | def get_filename(self, failobj=None): 94 | value = self.message.get_filename(failobj) 95 | if value is failobj: 96 | return value 97 | try: 98 | return str(value) 99 | except UnicodeDecodeError: 100 | return u'error decoding filename' 101 | 102 | # other convenience methods ############################################### 103 | 104 | def headers(self): 105 | """return an unicode string containing all the message's headers""" 106 | values = [] 107 | for header in list(self.message.keys()): 108 | values.append(u'%s: %s' % (header, self.get(header))) 109 | return '\n'.join(values) 110 | 111 | def multi_addrs(self, header): 112 | """return a list of 2-uple (name, address) for the given address (which 113 | is exepected to be an header containing address such as from, to, cc...) 114 | """ 115 | persons = [] 116 | for person in self.get_all(header, ()): 117 | name, mail = parseaddr(person) 118 | persons.append((name, mail)) 119 | return persons 120 | 121 | def date(self): 122 | """return a mx.DateTime object for the email's date or None if no date is 123 | set or if it can't be parsed 124 | """ 125 | value = self.get('date') 126 | if value: 127 | datetuple = parsedate(value) 128 | if datetuple: 129 | return DateTime(*datetuple[:6]) 130 | return None 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/ureports/docbook_writer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2002-2004 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """HTML formatting drivers for ureports 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import range 25 | from builtins import * 26 | 27 | __revision__ = "$Id: docbook_writer.py,v 1.4 2005-05-20 16:42:23 emb Exp $" 28 | 29 | from clonedigger.logilab.common.ureports import HTMLWriter 30 | 31 | class DocbookWriter(HTMLWriter): 32 | """format layouts as HTML""" 33 | 34 | def begin_format(self, layout): 35 | """begin to format a layout""" 36 | super(HTMLWriter, self).begin_format(layout) 37 | if self.snipet is None: 38 | self.writeln('') 39 | self.writeln(""" 40 | 42 | """) 43 | 44 | def end_format(self, layout): 45 | """finished to format a layout""" 46 | if self.snipet is None: 47 | self.writeln('') 48 | 49 | def visit_section(self, layout): 50 | """display a section (using (level 0) or
)""" 51 | if self.section == 0: 52 | tag = "chapter" 53 | else: 54 | tag = "section" 55 | self.section += 1 56 | self.writeln(self._indent('<%s%s>' % (tag, self.handle_attrs(layout)))) 57 | self.format_children(layout) 58 | self.writeln(self._indent(''% tag)) 59 | self.section -= 1 60 | 61 | def visit_title(self, layout): 62 | """display a title using """ 63 | self.write(self._indent(' <title%s>' % self.handle_attrs(layout))) 64 | self.format_children(layout) 65 | self.writeln('') 66 | 67 | def visit_table(self, layout): 68 | """display a table as html""" 69 | self.writeln(self._indent(' %s' \ 70 | % (self.handle_attrs(layout), layout.title))) 71 | self.writeln(self._indent(' '% layout.cols)) 72 | for i in range(layout.cols): 73 | self.writeln(self._indent(' ' % i)) 74 | 75 | table_content = self.get_table_content(layout) 76 | # write headers 77 | if layout.cheaders: 78 | self.writeln(self._indent(' ')) 79 | self._write_row(table_content[0]) 80 | self.writeln(self._indent(' ')) 81 | table_content = table_content[1:] 82 | elif layout.rcheaders: 83 | self.writeln(self._indent(' ')) 84 | self._write_row(table_content[-1]) 85 | self.writeln(self._indent(' ')) 86 | table_content = table_content[:-1] 87 | # write body 88 | self.writeln(self._indent(' ')) 89 | for i in range(len(table_content)): 90 | row = table_content[i] 91 | self.writeln(self._indent(' ')) 92 | for j in range(len(row)): 93 | cell = row[j] or ' ' 94 | self.writeln(self._indent(' %s' % cell)) 95 | self.writeln(self._indent(' ')) 96 | self.writeln(self._indent(' ')) 97 | self.writeln(self._indent(' ')) 98 | self.writeln(self._indent(' ')) 99 | 100 | def _write_row(self, row): 101 | """write content of row (using )""" 102 | self.writeln(' ') 103 | for j in range(len(row)): 104 | cell = row[j] or ' ' 105 | self.writeln(' %s' % cell) 106 | self.writeln(self._indent(' ')) 107 | 108 | def visit_list(self, layout): 109 | """display a list (using )""" 110 | self.writeln(self._indent(' ' % self.handle_attrs(layout))) 111 | for row in list(self.compute_content(layout)): 112 | self.writeln(' %s' % row) 113 | self.writeln(self._indent(' ')) 114 | 115 | def visit_paragraph(self, layout): 116 | """display links (using )""" 117 | self.write(self._indent(' ')) 118 | self.format_children(layout) 119 | self.writeln('') 120 | 121 | def visit_span(self, layout): 122 | """display links (using

)""" 123 | #TODO: translate in docbook 124 | self.write('' % self.handle_attrs(layout)) 125 | self.format_children(layout) 126 | self.write('') 127 | 128 | def visit_link(self, layout): 129 | """display links (using )""" 130 | self.write('%s' % (layout.url, 131 | self.handle_attrs(layout), 132 | layout.label)) 133 | 134 | def visit_verbatimtext(self, layout): 135 | """display verbatim text (using )""" 136 | self.writeln(self._indent(' ')) 137 | self.write(layout.data.replace('&', '&').replace('<', '<')) 138 | self.writeln(self._indent(' ')) 139 | 140 | def visit_text(self, layout): 141 | """add some text""" 142 | self.write(layout.data.replace('&', '&').replace('<', '<')) 143 | 144 | def _indent(self, string): 145 | """correctly indent string according to section""" 146 | return ' ' * 2*(self.section) + string 147 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/ureports/html_writer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2004-2005 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """HTML formatting drivers for ureports 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import range 25 | from builtins import * 26 | 27 | __revision__ = "$Id: html_writer.py,v 1.10 2006-03-08 09:47:29 katia Exp $" 28 | 29 | from cgi import escape 30 | 31 | from clonedigger.logilab.common.ureports import BaseWriter 32 | 33 | 34 | class HTMLWriter(BaseWriter): 35 | """format layouts as HTML""" 36 | 37 | def __init__(self, snipet=None): 38 | super(HTMLWriter, self).__init__(self) 39 | self.snipet = snipet 40 | 41 | def handle_attrs(self, layout): 42 | """get an attribute string from layout member attributes""" 43 | attrs = '' 44 | klass = getattr(layout, 'klass', None) 45 | if klass: 46 | attrs += ' class="%s"' % klass 47 | nid = getattr(layout, 'id', None) 48 | if nid: 49 | attrs += ' id="%s"' % nid 50 | return attrs 51 | 52 | def begin_format(self, layout): 53 | """begin to format a layout""" 54 | super(HTMLWriter, self).begin_format(layout) 55 | if self.snipet is None: 56 | self.writeln('') 57 | self.writeln('') 58 | 59 | def end_format(self, layout): 60 | """finished to format a layout""" 61 | if self.snipet is None: 62 | self.writeln('') 63 | self.writeln('') 64 | 65 | 66 | def visit_section(self, layout): 67 | """display a section as html, using div + h[section level]""" 68 | self.section += 1 69 | self.writeln('' % self.handle_attrs(layout)) 70 | self.format_children(layout) 71 | self.writeln('') 72 | self.section -= 1 73 | 74 | def visit_title(self, layout): 75 | """display a title using """ 76 | self.write('' % (self.section, self.handle_attrs(layout))) 77 | self.format_children(layout) 78 | self.writeln('' % self.section) 79 | 80 | def visit_table(self, layout): 81 | """display a table as html""" 82 | self.writeln('' % self.handle_attrs(layout)) 83 | table_content = self.get_table_content(layout) 84 | for i in range(len(table_content)): 85 | row = table_content[i] 86 | if i == 0 and layout.rheaders: 87 | self.writeln('') 88 | elif i+1 == len(table_content) and layout.rrheaders: 89 | self.writeln('') 90 | else: 91 | self.writeln('' % (i%2 and 'even' or 'odd')) 92 | for j in range(len(row)): 93 | cell = row[j] or ' ' 94 | if (layout.rheaders and i == 0) or \ 95 | (layout.cheaders and j == 0) or \ 96 | (layout.rrheaders and i+1 == len(table_content)) or \ 97 | (layout.rcheaders and j+1 == len(row)): 98 | self.writeln('%s' % cell) 99 | else: 100 | self.writeln('%s' % cell) 101 | self.writeln('') 102 | self.writeln('') 103 | 104 | def visit_list(self, layout): 105 | """display a list as html""" 106 | self.writeln('' % self.handle_attrs(layout)) 107 | for row in list(self.compute_content(layout)): 108 | self.writeln('

  • %s
  • ' % row) 109 | self.writeln('') 110 | 111 | def visit_paragraph(self, layout): 112 | """display links (using

    )""" 113 | self.write('

    ') 114 | self.format_children(layout) 115 | self.write('

    ') 116 | 117 | def visit_span(self, layout): 118 | """display links (using

    )""" 119 | self.write('' % self.handle_attrs(layout)) 120 | self.format_children(layout) 121 | self.write('') 122 | 123 | def visit_link(self, layout): 124 | """display links (using )""" 125 | self.write(' %s' % (layout.url, 126 | self.handle_attrs(layout), 127 | layout.label)) 128 | def visit_verbatimtext(self, layout): 129 | """display verbatim text (using

    )"""
    130 |         self.write('
    ')
    131 |         self.write(layout.data.replace('&', '&').replace('<', '<'))
    132 |         self.write('
    ') 133 | 134 | def visit_text(self, layout): 135 | """add some text""" 136 | data = layout.data 137 | if layout.escaped: 138 | data = data.replace('&', '&').replace('<', '<') 139 | self.write(data) 140 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/ureports/text_writer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2004-2005 LOGILAB S.A. (Paris, FRANCE). 2 | # http://www.logilab.fr/ -- mailto:contact@logilab.fr 3 | # 4 | # This program is free software; you can redistribute it and/or modify it under 5 | # the terms of the GNU General Public License as published by the Free Software 6 | # Foundation; either version 2 of the License, or (at your option) any later 7 | # version. 8 | # 9 | # This program is distributed in the hope that it will be useful, but WITHOUT 10 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 11 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 12 | # 13 | # You should have received a copy of the GNU General Public License along with 14 | # this program; if not, write to the Free Software Foundation, Inc., 15 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 | """Text formatting drivers for ureports""" 17 | from __future__ import print_function 18 | from __future__ import unicode_literals 19 | from __future__ import division 20 | from __future__ import absolute_import 21 | from future import standard_library 22 | standard_library.install_aliases() 23 | from builtins import range 24 | from builtins import * 25 | 26 | __revision__ = "$Id: text_writer.py,v 1.9 2005-11-22 13:13:13 syt Exp $" 27 | 28 | from os import linesep 29 | 30 | from clonedigger.logilab.common.ureports import BaseWriter 31 | 32 | TITLE_UNDERLINES = ['', '=', '-', '`', '.', '~', '^'] 33 | BULLETS = ['*', '-'] 34 | 35 | class TextWriter(BaseWriter): 36 | """format layouts as text 37 | (ReStructured inspiration but not totally handled yet) 38 | """ 39 | def begin_format(self, layout): 40 | super(TextWriter, self).begin_format(layout) 41 | self.list_level = 0 42 | self.pending_urls = [] 43 | 44 | def visit_section(self, layout): 45 | """display a section as text 46 | """ 47 | self.section += 1 48 | self.writeln() 49 | self.format_children(layout) 50 | if self.pending_urls: 51 | self.writeln() 52 | for label, url in self.pending_urls: 53 | self.writeln('.. _`%s`: %s' % (label, url)) 54 | self.pending_urls = [] 55 | self.section -= 1 56 | self.writeln() 57 | 58 | def visit_title(self, layout): 59 | title = ''.join(list(self.compute_content(layout))) 60 | self.writeln(title) 61 | try: 62 | self.writeln(TITLE_UNDERLINES[self.section] * len(title)) 63 | except IndexError: 64 | print("FIXME TITLE TOO DEEP. TURNING TITLE INTO TEXT") 65 | 66 | def visit_paragraph(self, layout): 67 | """enter a paragraph""" 68 | self.format_children(layout) 69 | self.writeln() 70 | 71 | def visit_span(self, layout): 72 | """enter a span""" 73 | self.format_children(layout) 74 | 75 | def visit_table(self, layout): 76 | """display a table as text""" 77 | table_content = self.get_table_content(layout) 78 | # get columns width 79 | cols_width = [0]*len(table_content[0]) 80 | for row in table_content: 81 | for index in range(len(row)): 82 | col = row[index] 83 | cols_width[index] = max(cols_width[index], len(col)) 84 | if layout.klass == 'field': 85 | self.field_table(layout, table_content, cols_width) 86 | else: 87 | self.default_table(layout, table_content, cols_width) 88 | self.writeln() 89 | 90 | def default_table(self, layout, table_content, cols_width): 91 | """format a table""" 92 | cols_width = [size+1 for size in cols_width] 93 | format_strings = ' '.join(['%%-%ss'] * len(cols_width)) 94 | format_strings = format_strings % tuple(cols_width) 95 | format_strings = format_strings.split(' ') 96 | table_linesep = '\n+' + '+'.join(['-'*w for w in cols_width]) + '+\n' 97 | headsep = '\n+' + '+'.join(['='*w for w in cols_width]) + '+\n' 98 | # FIXME: layout.cheaders 99 | self.write(table_linesep) 100 | for i in range(len(table_content)): 101 | self.write('|') 102 | line = table_content[i] 103 | for j in range(len(line)): 104 | self.write(format_strings[j] % line[j]) 105 | self.write('|') 106 | if i == 0 and layout.rheaders: 107 | self.write(headsep) 108 | else: 109 | self.write(table_linesep) 110 | 111 | def field_table(self, layout, table_content, cols_width): 112 | """special case for field table""" 113 | assert layout.cols == 2 114 | format_string = '%s%%-%ss: %%s' % (linesep, cols_width[0]) 115 | for field, value in table_content: 116 | self.write(format_string % (field, value)) 117 | 118 | 119 | def visit_list(self, layout): 120 | """display a list layout as text""" 121 | bullet = BULLETS[self.list_level % len(BULLETS)] 122 | indent = ' ' * self.list_level 123 | self.list_level += 1 124 | for child in layout.children: 125 | self.write('%s%s%s ' % (linesep, indent, bullet)) 126 | child.accept(self) 127 | self.list_level -= 1 128 | 129 | def visit_link(self, layout): 130 | """add a hyperlink""" 131 | if layout.label != layout.url: 132 | self.write('`%s`_' % layout.label) 133 | self.pending_urls.append( (layout.label, layout.url) ) 134 | else: 135 | self.write(layout.url) 136 | 137 | def visit_verbatimtext(self, layout): 138 | """display a verbatim layout as text (so difficult ;) 139 | """ 140 | self.writeln('::\n') 141 | for line in layout.data.splitlines(): 142 | self.writeln(' ' + line) 143 | self.writeln() 144 | 145 | def visit_text(self, layout): 146 | """add some text""" 147 | self.write(layout.data) 148 | 149 | 150 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/visitor.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """ Copyright (c) 2002-2003 LOGILAB S.A. (Paris, FRANCE). 14 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 15 | 16 | a generic visitor abstract implementation 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import next 25 | from builtins import * 26 | from builtins import object 27 | 28 | def no_filter(_): 29 | return 1 30 | 31 | 32 | # Iterators ################################################################### 33 | class FilteredIterator(object): 34 | 35 | def __init__(self, node, list_func, filter_func=None): 36 | self._next = [(node, 0)] 37 | if filter_func is None: 38 | filter_func = no_filter 39 | self._list = list_func(node, filter_func) 40 | 41 | def __next__(self): 42 | try: 43 | return self._list.pop(0) 44 | except : 45 | return None 46 | 47 | 48 | # Base Visitor ################################################################ 49 | class Visitor(object): 50 | 51 | def __init__(self, iterator_class, filter_func=None): 52 | self._iter_class = iterator_class 53 | self.filter = filter_func 54 | 55 | def visit(self, node, *args, **kargs): 56 | """ 57 | launch the visit on a given node 58 | 59 | call 'open_visit' before the begining of the visit, with extra args 60 | given 61 | when all nodes have been visited, call the 'close_visit' method 62 | """ 63 | self.open_visit(node, *args, **kargs) 64 | return self.close_visit(self._visit(node)) 65 | 66 | def _visit(self, node): 67 | iterator = self._get_iterator(node) 68 | n = next(iterator) 69 | while n: 70 | result = n.accept(self) 71 | n = next(iterator) 72 | return result 73 | 74 | def _get_iterator(self, node): 75 | return self._iter_class(node, self.filter) 76 | 77 | def open_visit(self, *args, **kargs): 78 | """ 79 | method called at the beginning of the visit 80 | """ 81 | pass 82 | 83 | def close_visit(self, result): 84 | """ 85 | method called at the end of the visit 86 | """ 87 | return result 88 | 89 | 90 | 91 | # standard visited mixin ###################################################### 92 | class VisitedMixIn(object): 93 | """ 94 | Visited interface allow node visitors to use the node 95 | """ 96 | def get_visit_name(self): 97 | """ 98 | return the visit name for the mixed class. When calling 'accept', the 99 | method <'visit_' + name returned by this method> will be called on the 100 | visitor 101 | """ 102 | try: 103 | return self.TYPE.replace('-', '_') 104 | except: 105 | return self.__class__.__name__.lower() 106 | 107 | def accept(self, visitor, *args, **kwargs): 108 | func = getattr(visitor, 'visit_%s' % self.get_visit_name()) 109 | return func(self, *args, **kwargs) 110 | 111 | def leave(self, visitor, *args, **kwargs): 112 | func = getattr(visitor, 'leave_%s' % self.get_visit_name()) 113 | return func(self, *args, **kwargs) 114 | 115 | 116 | -------------------------------------------------------------------------------- /clonedigger/logilab/common/xmlrpcutils.py: -------------------------------------------------------------------------------- 1 | # This program is free software; you can redistribute it and/or modify it under 2 | # the terms of the GNU General Public License as published by the Free Software 3 | # Foundation; either version 2 of the License, or (at your option) any later 4 | # version. 5 | # 6 | # This program is distributed in the hope that it will be useful, but WITHOUT 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details 9 | # 10 | # You should have received a copy of the GNU General Public License along with 11 | # this program; if not, write to the Free Software Foundation, Inc., 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 13 | """XML-RPC utilities 14 | 15 | Copyright (c) 2003-2004 LOGILAB S.A. (Paris, FRANCE). 16 | http://www.logilab.fr/ -- mailto:contact@logilab.fr 17 | """ 18 | from __future__ import unicode_literals 19 | from __future__ import print_function 20 | from __future__ import division 21 | from __future__ import absolute_import 22 | from future import standard_library 23 | standard_library.install_aliases() 24 | from builtins import str 25 | from builtins import * 26 | from builtins import object 27 | 28 | __revision__ = "$Id: xmlrpcutils.py,v 1.3 2005-11-22 13:13:03 syt Exp $" 29 | 30 | import xmlrpc.client 31 | from base64 import encodestring 32 | #from cStringIO import StringIO 33 | 34 | ProtocolError = xmlrpc.client.ProtocolError 35 | 36 | ## class BasicAuthTransport(xmlrpclib.Transport): 37 | ## def __init__(self, username=None, password=None): 38 | ## self.username = username 39 | ## self.password = password 40 | ## self.verbose = None 41 | ## self.has_ssl = httplib.__dict__.has_key("HTTPConnection") 42 | 43 | ## def request(self, host, handler, request_body, verbose=None): 44 | ## # issue XML-RPC request 45 | ## if self.has_ssl: 46 | ## if host.startswith("https:"): h = httplib.HTTPSConnection(host) 47 | ## else: h = httplib.HTTPConnection(host) 48 | ## else: h = httplib.HTTP(host) 49 | 50 | ## h.putrequest("POST", handler) 51 | 52 | ## # required by HTTP/1.1 53 | ## if not self.has_ssl: # HTTPConnection already does 1.1 54 | ## h.putheader("Host", host) 55 | ## h.putheader("Connection", "close") 56 | 57 | ## if request_body: h.send(request_body) 58 | ## if self.has_ssl: 59 | ## response = h.getresponse() 60 | ## if response.status != 200: 61 | ## raise xmlrpclib.ProtocolError(host + handler, 62 | ## response.status, 63 | ## response.reason, 64 | ## response.msg) 65 | ## file = response.fp 66 | ## else: 67 | ## errcode, errmsg, headers = h.getreply() 68 | ## if errcode != 200: 69 | ## raise xmlrpclib.ProtocolError(host + handler, errcode, 70 | ## errmsg, headers) 71 | 72 | ## file = h.getfile() 73 | 74 | ## return self.parse_response(file) 75 | 76 | 77 | 78 | class AuthMixin(object): 79 | """basic http authentication mixin for xmlrpc transports""" 80 | 81 | def __init__(self, username, password, encoding): 82 | self.verbose = 0 83 | self.username = username 84 | self.password = password 85 | self.encoding = encoding 86 | 87 | def request(self, host, handler, request_body, verbose=0): 88 | """issue XML-RPC request""" 89 | h = self.make_connection(host) 90 | h.putrequest("POST", handler) 91 | # required by XML-RPC 92 | h.putheader("User-Agent", self.user_agent) 93 | h.putheader("Content-Type", "text/xml") 94 | h.putheader("Content-Length", str(len(request_body))) 95 | h.putheader("Host", host) 96 | h.putheader("Connection", "close") 97 | # basic auth 98 | if self.username is not None and self.password is not None: 99 | h.putheader("AUTHORIZATION", "Basic %s" % encodestring( 100 | "%s:%s" % (self.username, self.password)).replace("\012", "")) 101 | h.endheaders() 102 | # send body 103 | if request_body: 104 | h.send(request_body) 105 | # get and check reply 106 | errcode, errmsg, headers = h.getreply() 107 | if errcode != 200: 108 | raise ProtocolError(host + handler, errcode, errmsg, headers) 109 | file = h.getfile() 110 | ## # FIXME: encoding ??? iirc, this fix a bug in xmlrpclib but... 111 | ## data = h.getfile().read() 112 | ## if self.encoding != 'UTF-8': 113 | ## data = data.replace("version='1.0'", 114 | ## "version='1.0' encoding='%s'" % self.encoding) 115 | ## result = StringIO() 116 | ## result.write(data) 117 | ## result.seek(0) 118 | ## return self.parse_response(result) 119 | return self.parse_response(file) 120 | 121 | class BasicAuthTransport(AuthMixin, xmlrpc.client.Transport): 122 | """basic http authentication transport""" 123 | 124 | class BasicAuthSafeTransport(AuthMixin, xmlrpc.client.SafeTransport): 125 | """basic https authentication transport""" 126 | 127 | 128 | def connect(url, user=None, passwd=None, encoding='ISO-8859-1'): 129 | """return an xml rpc server on , using user / password if specified 130 | """ 131 | if user or passwd: 132 | assert user and passwd is not None 133 | if url.startswith('https://'): 134 | transport = BasicAuthSafeTransport(user, passwd, encoding) 135 | else: 136 | transport = BasicAuthTransport(user, passwd, encoding) 137 | else: 138 | transport = None 139 | server = xmlrpc.client.ServerProxy(url, transport, encoding=encoding) 140 | return server 141 | -------------------------------------------------------------------------------- /clonedigger/lua_antlr.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from __future__ import absolute_import 3 | from __future__ import unicode_literals 4 | from __future__ import division 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import * 8 | from builtins import object 9 | # Copyright 2008 Peter Bulychev 10 | # http://clonedigger.sourceforge.net 11 | # 12 | # This file is part of Clone Digger. 13 | # 14 | # Clone Digger is free software: you can redistribute it and/or modify 15 | # it under the terms of the GNU General Public License as published by 16 | # the Free Software Foundation, either version 3 of the License, or 17 | # (at your option) any later version. 18 | # 19 | # Clone Digger is distributed in the hope that it will be useful, 20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | # GNU General Public License for more details. 23 | # 24 | # You should have received a copy of the GNU General Public License 25 | # along with Clone Digger. If not, see . 26 | 27 | import os 28 | import xml.parsers.expat 29 | 30 | from .abstract_syntax_tree import * 31 | 32 | class LuaANTLRSourceFile (SourceFile): 33 | extension = 'lua' 34 | size_threshold = 5 35 | distance_threshold = 5 36 | def __init__(self, file_name): 37 | SourceFile.__init__(self, file_name) 38 | class ExpatHandler(object): 39 | def __init__(self, start_node, parent): 40 | self.parent = parent 41 | self.stack = [start_node] 42 | def start_element(expat_self, xml_node_name, attrs): 43 | line_number = int(attrs["line_number"])-1 44 | line_numbers = [line_number] 45 | if line_numbers == [-1]: 46 | line_numbers = [] 47 | name = attrs["name"] 48 | r = AbstractSyntaxTree(name, line_numbers, self) 49 | if name in ["stat", "chunk"]: 50 | r.markAsStatement() 51 | else: 52 | assert(xml_node_name == "node") 53 | expat_self.stack[-1].addChild(r) 54 | expat_self.stack.append(r) 55 | def end_element(self, name): 56 | self.stack.pop() 57 | 58 | tree_file_name = 'temporary_ast.xml' 59 | producer_class_path = os.path.join('.','lua_antlr', 'TreeProducer.jar') 60 | antlr_class_path = os.path.join('.','antlr_runtime','antlr-runtime-3.1.jar') 61 | if os.name in ['mac', 'posix']: 62 | class_path_delimeter = ':' 63 | elif os.name in ['nt', 'dos', 'ce']: 64 | class_path_delimeter = ';' 65 | else: 66 | print('unsupported OS') 67 | assert(0) 68 | 69 | if os.system('java -classpath ' + producer_class_path + class_path_delimeter + antlr_class_path + ' TreeProducer %s %s 2>err.log'%(file_name, tree_file_name)): 70 | f = open('err.log') 71 | s = f.read() 72 | f.close() 73 | raise s 74 | f = open('err.log') 75 | s = f.read() 76 | f.close() 77 | if s: 78 | print(s) 79 | 80 | self._tree = AbstractSyntaxTree('program') 81 | handler = ExpatHandler(self._tree, self) 82 | p = xml.parsers.expat.ParserCreate() 83 | p.StartElementHandler = handler.start_element 84 | p.EndElementHandler = handler.end_element 85 | f = open(tree_file_name) 86 | p.ParseFile(f) 87 | f.close() 88 | # os.remove(tree_file_name) 89 | -------------------------------------------------------------------------------- /clonedigger/lua_antlr/Lua.g: -------------------------------------------------------------------------------- 1 | /* 2 | * Lua 5.1 grammar 3 | * 4 | * Nicolai Mainiero 5 | * May 2007 6 | * 7 | * This is a Lua (http://www.lua.org) grammar for the version 5.1 for ANTLR 3. 8 | * I tested it with basic and extended examples and it worked fine. It is also used 9 | * for LunarEclipse (http://lunareclipse.sf.net) a Lua editor based on Eclipse. 10 | * 11 | * Thanks to Johannes Luber and Gavin Lambert who helped me with some mutually left recursion. 12 | * 13 | */ 14 | 15 | grammar Lua; 16 | 17 | options { 18 | backtrack=true; 19 | } 20 | 21 | chunk : (stat (';')?)* (laststat (';')?)?; 22 | 23 | block : chunk; 24 | 25 | stat : varlist1 '=' explist1 | 26 | functioncall | 27 | 'do' block 'end' | 28 | 'while' exp 'do' block 'end' | 29 | 'repeat' block 'until' exp | 30 | 'if' exp 'then' block ('elseif' exp 'then' block)* ('else' block)? 'end' | 31 | 'for' NAME '=' exp ',' exp (',' exp)? 'do' block 'end' | 32 | 'for' namelist 'in' explist1 'do' block 'end' | 33 | 'function' funcname funcbody | 34 | 'local' 'function' NAME funcbody | 35 | 'local' namelist ('=' explist1)? ; 36 | 37 | laststat : 'return' (explist1)? | 'break'; 38 | 39 | funcname : NAME ('.' NAME)* (':' NAME)? ; 40 | 41 | varlist1 : var (',' var)*; 42 | 43 | 44 | namelist : NAME (',' NAME)*; 45 | 46 | explist1 : (exp ',')* exp; 47 | 48 | exp : ('nil' | 'false' | 'true' | number | string | '...' | function | prefixexp | tableconstructor | unop exp) (binop exp)* ; 49 | 50 | var: (NAME | '(' exp ')' varSuffix) varSuffix*; 51 | 52 | prefixexp: varOrExp nameAndArgs*; 53 | 54 | functioncall: varOrExp nameAndArgs+; 55 | 56 | /* 57 | var : NAME | prefixexp '[' exp ']' | prefixexp '.' NAME; 58 | 59 | prefixexp : var | functioncall | '(' exp ')'; 60 | 61 | functioncall : prefixexp args | prefixexp ':' NAME args ; 62 | */ 63 | 64 | varOrExp: var | '(' exp ')'; 65 | 66 | nameAndArgs: (':' NAME)? args; 67 | 68 | varSuffix: nameAndArgs* ('[' exp ']' | '.' NAME); 69 | 70 | args : '(' (explist1)? ')' | tableconstructor | string ; 71 | 72 | function : 'function' funcbody; 73 | 74 | funcbody : '(' (parlist1)? ')' block 'end'; 75 | 76 | parlist1 : namelist (',' '...')? | '...'; 77 | 78 | tableconstructor : '{' (fieldlist)? '}'; 79 | 80 | fieldlist : field (fieldsep field)* (fieldsep)?; 81 | 82 | field : '[' exp ']' '=' exp | NAME '=' exp | exp; 83 | 84 | fieldsep : ',' | ';'; 85 | 86 | binop : '+' | '-' | '*' | '/' | '^' | '%' | '..' | 87 | '<' | '<=' | '>' | '>=' | '==' | '~=' | 88 | 'and' | 'or'; 89 | 90 | unop : '-' | 'not' | '#'; 91 | 92 | number : INT | FLOAT | EXP | HEX; 93 | 94 | string : NORMALSTRING | CHARSTRING | LONGSTRING; 95 | 96 | 97 | // LEXER 98 | 99 | NAME :('a'..'z'|'A'..'Z'|'_')(options{greedy=true;}: 'a'..'z'|'A'..'Z'|'_'|'0'..'9')* 100 | ; 101 | 102 | INT : ('0'..'9')+; 103 | 104 | FLOAT :INT '.' INT ; 105 | 106 | EXP : (INT| FLOAT) ('E'|'e') ('-')? INT; 107 | 108 | HEX :'0x' ('0'..'9'| 'a'..'f')+ ; 109 | 110 | 111 | 112 | NORMALSTRING 113 | : '"' ( EscapeSequence | ~('\\'|'"') )* '"' 114 | ; 115 | 116 | CHARSTRING 117 | : '\'' ( EscapeSequence | ~('\''|'\\') )* '\'' 118 | ; 119 | 120 | LONGSTRING 121 | : '['('=')*'[' ( EscapeSequence | ~('\\'|']') )* ']'('=')*']' 122 | ; 123 | 124 | fragment 125 | EscapeSequence 126 | : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') 127 | | UnicodeEscape 128 | | OctalEscape 129 | ; 130 | 131 | fragment 132 | OctalEscape 133 | : '\\' ('0'..'3') ('0'..'7') ('0'..'7') 134 | | '\\' ('0'..'7') ('0'..'7') 135 | | '\\' ('0'..'7') 136 | ; 137 | 138 | fragment 139 | UnicodeEscape 140 | : '\\' 'u' HexDigit HexDigit HexDigit HexDigit 141 | ; 142 | 143 | fragment 144 | HexDigit : ('0'..'9'|'a'..'f'|'A'..'F') ; 145 | 146 | 147 | COMMENT 148 | : '--[[' ( options {greedy=false;} : . )* ']]' {skip();} 149 | ; 150 | 151 | LINE_COMMENT 152 | : '--' ~('\n'|'\r')* '\r'? '\n' {skip();} 153 | ; 154 | 155 | 156 | WS : (' '|'\t'|'\u000C') {skip();} 157 | ; 158 | 159 | NEWLINE : ('\r')? '\n' {skip();} 160 | ; 161 | -------------------------------------------------------------------------------- /clonedigger/lua_antlr/TreeProducer.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/clonedigger/lua_antlr/TreeProducer.jar -------------------------------------------------------------------------------- /clonedigger/lua_antlr/TreeProducer.java: -------------------------------------------------------------------------------- 1 | /* Copyright 2008 Peter Bulychev 2 | * 3 | * This file is part of Clone Digger. 4 | * 5 | * Clone Digger is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * Clone Digger is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with Clone Digger. If not, see . 17 | */ 18 | import org.antlr.runtime.*; 19 | import org.antlr.stringtemplate.*; 20 | import org.antlr.runtime.tree.*; 21 | 22 | import org.antlr.runtime.tree.ParseTree; 23 | 24 | import org.antlr.runtime.*; 25 | import org.antlr.runtime.tree.*; 26 | import org.antlr.runtime.debug.*; 27 | 28 | import java.lang.reflect.*; 29 | import java.io.*; 30 | import java.util.*; 31 | import java.text.*; 32 | import java.lang.*; 33 | 34 | 35 | 36 | public class TreeProducer 37 | { 38 | public TreeProducer () 39 | { 40 | super (); 41 | } 42 | 43 | /* 44 | * forXml function was taken from http://www.javapractices.com/topic/TopicAction.do?Id=96 45 | * the license is: http://creativecommons.org/licenses/by/3.0/ 46 | */ 47 | public static String forXML (String aText) 48 | { 49 | final StringBuilder result = new StringBuilder (); 50 | final StringCharacterIterator iterator = 51 | new StringCharacterIterator (aText); 52 | char character = iterator.current (); 53 | while (character != CharacterIterator.DONE) 54 | { 55 | if (character == '<') 56 | { 57 | result.append ("<"); 58 | } 59 | else if (character == '>') 60 | { 61 | result.append (">"); 62 | } 63 | else if (character == '\"') 64 | { 65 | result.append ("""); 66 | } 67 | else if (character == '\'') 68 | { 69 | result.append ("'"); 70 | } 71 | else if (character == '&') 72 | { 73 | result.append ("&"); 74 | } 75 | else 76 | { 77 | //the char is not a special one 78 | // //add it to the result as is 79 | result.append (character); 80 | } 81 | character = iterator.next (); 82 | } 83 | return result.toString (); 84 | } 85 | // } 86 | 87 | public static void printTree (ParseTree tree, PrintWriter outputStream, String indent) 88 | { 89 | // String xml_node_name = (tree.is_statement?"statement_node":"node"); 90 | String xml_node_name = "node"; 91 | int lineno; 92 | if ( tree.payload instanceof Token ) { 93 | Token t = (Token)tree.payload; 94 | lineno = t.getLine(); 95 | } else { 96 | lineno = 0; 97 | } 98 | 99 | outputStream.println (indent + "<" + xml_node_name + " name=\"" + forXML ("" + tree) + "\"" + 100 | " line_number=\"" + lineno + "\" " + 101 | ">"); 102 | for (int i = 0; i < tree.getChildCount (); i += 1) 103 | { 104 | printTree ((ParseTree )tree.getChild (i), outputStream, indent + " "); 105 | } 106 | outputStream.println (indent + ""); 107 | } 108 | 109 | public static void main (String[]args) throws Exception 110 | { 111 | ANTLRFileStream input = new ANTLRFileStream (args[0]); 112 | LuaLexer lexer = new LuaLexer (input); 113 | CommonTokenStream tokens = new CommonTokenStream (lexer); 114 | 115 | ParseTreeBuilder builder = new ParseTreeBuilder("chunk"); 116 | 117 | LuaParser parser = new LuaParser (tokens, builder); 118 | 119 | parser.chunk(); 120 | ParseTree tree = builder.getTree(); 121 | 122 | PrintWriter outputStream = 123 | new PrintWriter (new FileWriter (args[1], false)); 124 | outputStream.println (""); 125 | printTree (tree, outputStream, ""); 126 | outputStream.close (); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /clonedigger/lua_antlr/build_jar.sh: -------------------------------------------------------------------------------- 1 | export CLASSPATH=/home/peter/antlr/antlr-3.1.jar:/home/peter/antlr/antlr-3.0.1/lib/stringtemplate-3.1b1.jar:/home/peter/antlr/antlr-3.0.1/lib/antlr-2.7.7.jar:. 2 | java org.antlr.Tool -debug Lua.g 3 | javac *.java 4 | jar -cf TreeProducer.jar *.class 5 | rm *.class 6 | -------------------------------------------------------------------------------- /clonedigger/suffix_tree.py: -------------------------------------------------------------------------------- 1 | from __future__ import unicode_literals 2 | from __future__ import print_function 3 | from __future__ import division 4 | from __future__ import absolute_import 5 | from future import standard_library 6 | standard_library.install_aliases() 7 | from builtins import str 8 | from builtins import range 9 | from builtins import * 10 | from builtins import object 11 | # Copyright 2008 Peter Bulychev 12 | # http://clonedigger.sourceforge.net 13 | # 14 | # This file is part of Clone Digger. 15 | # 16 | # Clone Digger is free software: you can redistribute it and/or modify 17 | # it under the terms of the GNU General Public License as published by 18 | # the Free Software Foundation, either version 3 of the License, or 19 | # (at your option) any later version. 20 | # 21 | # Clone Digger is distributed in the hope that it will be useful, 22 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 24 | # GNU General Public License for more details. 25 | # 26 | # You should have received a copy of the GNU General Public License 27 | # along with Clone Digger. If not, see . 28 | 29 | 30 | class SuffixTree(object): 31 | class StringPosition(object): 32 | def __init__(self, string, position,prevelem): 33 | self.string = string 34 | self.position = position 35 | self.prevelem = prevelem 36 | class SuffixTreeNode(object): 37 | def __init__(self): 38 | self.childs = {} # 39 | self.string_positions = [] 40 | self.ending_strings = [] 41 | 42 | def __init__(self, f_code): 43 | self._node = self.SuffixTreeNode() 44 | self._f_code = f_code 45 | def _add(self, string, prevelem): 46 | pos = 0 47 | node = self._node 48 | for pos in range(len(string)): 49 | e = string[pos] 50 | code = self._f_code(e) 51 | node.string_positions.append(self.StringPosition(string, pos, prevelem)) 52 | if code not in node.childs: 53 | node.childs[code] = self.SuffixTreeNode() 54 | node = node.childs[code] 55 | node.ending_strings.append(self.StringPosition(string, pos+1, prevelem)) 56 | def add(self, string): 57 | for i in range(len(string)): 58 | if i == 0: 59 | prevelem = None 60 | else: 61 | prevelem = self._f_code(string[i-1]) 62 | self._add(string[i:],prevelem) 63 | def getBestMaxSubstrings(self, threshold, f, f_elem, node = None, initial_threshold=None): 64 | if initial_threshold==None: 65 | initial_threshold = threshold 66 | def check_left_diverse_and_add(s1, s2, p): 67 | if ((s1.prevelem == None) or (s2.prevelem == None) or (s1.prevelem != s2.prevelem)) and s1.position>p: 68 | candidate = (s1.string[:s1.position-p], s2.string[:s2.position-p]) 69 | if f_elem(candidate[0]) >= initial_threshold or \ 70 | f_elem(candidate[1]) >= initial_threshold: 71 | r.append(candidate) 72 | return True 73 | else: 74 | return False 75 | if node == None: 76 | node = self._node 77 | r = [] 78 | if threshold <= 0: 79 | for s1 in node.ending_strings: 80 | for s2 in node.string_positions: 81 | if s1.string == s2.string: 82 | continue 83 | check_left_diverse_and_add(s1, s2, 0) 84 | for i in range(len(node.ending_strings)): 85 | for j in range(i): 86 | s1 = node.ending_strings[i] 87 | s2 = node.ending_strings[j] 88 | check_left_diverse_and_add(s1, s2, 0) 89 | for i in range(len(list(node.childs.keys()))): 90 | for j in range(i): 91 | c1 = list(node.childs.keys())[i] 92 | c2 = list(node.childs.keys())[j] 93 | for s1 in node.childs[c1].string_positions + node.childs[c1].ending_strings: 94 | for s2 in node.childs[c2].string_positions + node.childs[c2].ending_strings: 95 | check_left_diverse_and_add(s1, s2, 1) 96 | for (code, child) in list(node.childs.items()): 97 | r += self.getBestMaxSubstrings(threshold - f(code), f, f_elem, child, initial_threshold) 98 | return r 99 | 100 | if __name__ == '__main__': 101 | class Elem(object): 102 | def __init__(self, code): 103 | self._code = code 104 | def getCode(self): 105 | return self._code 106 | def __str__(self): 107 | return str(self._code) 108 | def test1(): 109 | t = SuffixTree() 110 | for w in ['abcPeter', 'Pet1erbca', 'Peter', 'aPet0--']: 111 | t.add([Elem(c) for c in w]) 112 | maxs = t.getBestMaxSubstrings(3) 113 | l = [] 114 | for (s1, s2) in maxs: 115 | l.append([''.join([str(e) for e in s1]), ''.join([str(e) for e in s2])]) 116 | assert(l == [['Pe1t', 'P2et'], ['P3et', 'Pe4t'], ['Pet', 'Pet'], ['Pet', 'Pet'], ['Pet', 'Pet'], ['Peter', 'Peter']]) 117 | def test2(): 118 | t = SuffixTree() 119 | for w in ['a', 'aa']: 120 | t.add([Elem(c) for c in w]) 121 | maxs = t.getBestMaxSubstrings(0) 122 | l = [] 123 | for (s1, s2) in maxs: 124 | l.append([''.join([str(e) for e in s1]), ''.join([str(e) for e in s2])]) 125 | assert(l == [['a', 'a'], ['a', 'a'], ['a', 'a']]) 126 | for s in dir(): 127 | if s.find('test') == 0: 128 | eval(s + '()') 129 | 130 | -------------------------------------------------------------------------------- /eclipse_plugin_manual/Run.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/Run.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/RunDone.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/RunDone.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/RunFirst.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/RunFirst.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/RunInstall.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/RunInstall.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/RunPopup.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/RunPopup.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/SUpdate.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/SUpdate.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/SUpdateAdd.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/SUpdateAdd.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/SUpdateInstall.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/SUpdateInstall.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/Update.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/eclipse_plugin_manual/Update.gif -------------------------------------------------------------------------------- /eclipse_plugin_manual/eclipse_plugin_manual.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | CloneDigger Eclipse plugin manual 4 | 5 | 6 | 7 | Requirements 8 |
      9 |
    • Eclipse 3.4
    • 10 |
    11 | Install from SVN 12 |

     Go to the update manager (inside the help menu) and 13 | add update site: 14 | http://clonedigger.svn.sourceforge.net/svnroot/clonedigger/trunk/org.clonedigger.feature/ 15 | (Eclipse should do the rest) 16 |

    17 |   18 | 19 |
    Using 20 |

    Now, you can check your projects for clones. Just run 21 | clonedigger 22 | wizard from main menu.

    23 | 24 |

    On the first page of a wizard you may select files to dig, 25 | choose 26 | language (for now clonedigger support only java and python) and select 27 | digging options (fast mode clone size and clone distance). Click "next" button when you will 28 | ready .

    29 | 30 |

    On the first run plugin will try to download the last version 31 | of 32 | clonedigger from PyPi repository.

    33 | 34 |

    After that you will see the 35 | console output during the dig phase. When Clone Digger will ready you may press final button.

    36 | 37 |

    Now you will see the report. Before each clone there is a "Go 38 | to this 39 | fragment in Eclipse" link, you may follow this links to automatically 40 | find and select clone in eclipse environment.

    41 |

    Tip: be careful! When you will edit your 42 | code and 43 | add some new lines to it report will gone out of sync and "Go to this 44 | fragment in Eclipse" links will be broken.

    45 |

    Feature: you may run clonedigger wizard 46 | from project 47 | tree, just select desired files or folders by holding {ctrl} button and 48 | this file will be checked on the first wizard page when it appear.

    49 |
    Update CloneDigger 50 | instance
    51 |

    You can update clonedigger instance in plugin by clicking 52 | Update 53 | CloneDigger menu item. CloneDigger will be downloaded next time you run 54 | the wizard.

    by Anatoly Zapadinsky

    -------------------------------------------------------------------------------- /org.clonedigger.feature/build.properties: -------------------------------------------------------------------------------- 1 | bin.includes = feature.xml 2 | src.includes = .project,\ 3 | feature.xml,\ 4 | build.properties,\ 5 | site.xml 6 | -------------------------------------------------------------------------------- /org.clonedigger.feature/feature.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | [Enter Feature Description here.] 10 | 11 | 12 | 13 | ... 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.3.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.4.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.5.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.6.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.7.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/features/org.clonedigger.feature_1.1.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/features/org.clonedigger.feature_1.1.8.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.3.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.4.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.5.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.6.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.6.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.7.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/plugins/org.clonedigger_1.1.8.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger.feature/plugins/org.clonedigger_1.1.8.jar -------------------------------------------------------------------------------- /org.clonedigger.feature/site.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /org.clonedigger/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /org.clonedigger/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | #Thu Jul 24 12:47:50 MSD 2008 2 | eclipse.preferences.version=1 3 | encoding/setup.py=UTF-8 4 | -------------------------------------------------------------------------------- /org.clonedigger/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | #Wed Jul 23 21:54:52 MSD 2008 2 | eclipse.preferences.version=1 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 4 | org.eclipse.jdt.core.compiler.compliance=1.5 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.source=1.5 8 | -------------------------------------------------------------------------------- /org.clonedigger/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: Helloworld Plug-in 4 | Bundle-SymbolicName: org.clonedigger;singleton:=true 5 | Bundle-Version: 1.1.8 6 | Bundle-Activator: org.clonedigger.Activator 7 | Bundle-Vendor: Clone Digger 8 | Require-Bundle: org.eclipse.ui, 9 | org.eclipse.core.runtime, 10 | org.eclipse.ui.ide, 11 | org.eclipse.core.resources;bundle-version="3.2.0", 12 | org.eclipse.ui.editors;bundle-version="3.2.0", 13 | org.eclipse.ui.browser;bundle-version="3.2.0", 14 | org.python.pydev;bundle-version="1.3.18" 15 | Bundle-RequiredExecutionEnvironment: J2SE-1.5 16 | Import-Package: org.eclipse.core.filesystem, 17 | org.eclipse.jdt.core, 18 | org.eclipse.jface.text 19 | Export-Package: org.clonedigger, 20 | org.clonedigger.actions 21 | Bundle-ActivationPolicy: lazy 22 | -------------------------------------------------------------------------------- /org.clonedigger/build.properties: -------------------------------------------------------------------------------- 1 | source.. = src/ 2 | output.. = bin/ 3 | bin.includes = plugin.xml,\ 4 | META-INF/,\ 5 | .,\ 6 | runclonedigger.py,\ 7 | bin/,\ 8 | icons/,\ 9 | setup.py,\ 10 | ez_setup.py 11 | src.includes = src/,\ 12 | plugin.xml,\ 13 | icons/,\ 14 | META-INF/,\ 15 | runclonedigger.py,\ 16 | .project,\ 17 | .settings/,\ 18 | .pydevproject,\ 19 | .classpath,\ 20 | build.properties,\ 21 | bin/,\ 22 | setup.py,\ 23 | ez_setup.py 24 | -------------------------------------------------------------------------------- /org.clonedigger/icons/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jlachowski/clonedigger/f5f2a182a35f880c0c345db3d240ddb20ecfb09d/org.clonedigger/icons/icon.gif -------------------------------------------------------------------------------- /org.clonedigger/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 10 | 13 | 15 | 16 | 17 | 25 | 26 | 33 | 34 | 35 | 36 | 38 | 43 | 44 | 45 | 47 | 50 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /org.clonedigger/runclonedigger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from __future__ import print_function 3 | from __future__ import unicode_literals 4 | from __future__ import division 5 | from __future__ import absolute_import 6 | from future import standard_library 7 | standard_library.install_aliases() 8 | from builtins import * 9 | import sys 10 | import os 11 | python_path = os.environ['PYTHONPATH'] 12 | try: 13 | import clonedigger.clonedigger 14 | if not os.path.abspath(clonedigger.clonedigger.__file__).startswith(os.path.abspath(python_path)): 15 | raise ImportError 16 | except ImportError: 17 | if not os.path.exists(python_path): 18 | os.mkdir(python_path) 19 | os.chdir(python_path) 20 | print('Missing Clone Digger') 21 | print('We will try now to install it to local directory', python_path) 22 | print('please wait...') 23 | sys.argv = [sys.argv[0], 'easy_install', '--exclude-scripts', '-U', '--always-copy', '--install-dir', python_path, 'clonedigger'] 24 | try: 25 | import setup 26 | except: 27 | import setup 28 | sys.exit(143) 29 | clonedigger.clonedigger.main() 30 | -------------------------------------------------------------------------------- /org.clonedigger/setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | This module contains the tool of collective.recipe.buildbot 4 | """ 5 | from __future__ import unicode_literals 6 | from __future__ import print_function 7 | from __future__ import division 8 | from __future__ import absolute_import 9 | from future import standard_library 10 | standard_library.install_aliases() 11 | from builtins import * 12 | 13 | from ez_setup import use_setuptools 14 | use_setuptools() 15 | 16 | import os 17 | from setuptools import setup, find_packages 18 | 19 | def read(*rnames): 20 | return open(os.path.join(os.getcwd(), *rnames)).read() 21 | 22 | version = '1.0.4-beta' 23 | 24 | long_description = "" 25 | 26 | entry_points = {"console_scripts": [ 27 | "clonedigger = clonedigger.clonedigger:main" 28 | ], 29 | } 30 | 31 | setup(name='clonedigger', 32 | version=version, 33 | description=("Clone Digger aimed to detect similar code in Python " 34 | "and Java programs."), 35 | long_description=long_description, 36 | # Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers 37 | classifiers=[ 38 | 'Intended Audience :: Developers', 39 | 'Topic :: Software Development :: Libraries :: Python Modules', 40 | ], 41 | keywords='buildout buildbot', 42 | author='Peter Bulychev', 43 | author_email='peter.bulychev@gmail.com', 44 | url='http://clonedigger.sourceforge.net', 45 | license='GPL', 46 | packages=find_packages(), 47 | include_package_data=True, 48 | zip_safe=False, 49 | install_requires=['setuptools'], 50 | entry_points=entry_points, 51 | ) 52 | 53 | -------------------------------------------------------------------------------- /org.clonedigger/src/org/clonedigger/Activator.java: -------------------------------------------------------------------------------- 1 | package org.clonedigger; 2 | 3 | import org.eclipse.core.runtime.IStatus; 4 | import org.eclipse.core.runtime.Status; 5 | import org.eclipse.jface.resource.ImageDescriptor; 6 | import org.eclipse.ui.plugin.AbstractUIPlugin; 7 | import org.osgi.framework.BundleContext; 8 | 9 | /** 10 | * The activator class controls the plug-in life cycle 11 | */ 12 | public class Activator extends AbstractUIPlugin { 13 | 14 | // The plug-in ID 15 | public static final String PLUGIN_ID = "org.clonedigger"; 16 | 17 | // The shared instance 18 | private static Activator plugin; 19 | 20 | public Activator() { 21 | } 22 | 23 | /* 24 | * (non-Javadoc) 25 | * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) 26 | */ 27 | public void start(BundleContext context) throws Exception { 28 | super.start(context); 29 | plugin = this; 30 | } 31 | 32 | /* 33 | * (non-Javadoc) 34 | * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) 35 | */ 36 | public void stop(BundleContext context) throws Exception { 37 | plugin = null; 38 | super.stop(context); 39 | } 40 | 41 | /** 42 | * Returns the shared instance 43 | * 44 | * @return the shared instance 45 | */ 46 | public static Activator getDefault() { 47 | return plugin; 48 | } 49 | 50 | public static void log(Throwable e) { 51 | try { 52 | Status s = new Status(IStatus.ERROR, PLUGIN_ID, 53 | e.getMessage() != null ? e.getMessage() : "No message gotten.", e); 54 | getDefault().getLog().log(s); 55 | } catch (Throwable e1) { 56 | //logging should never fail! 57 | } 58 | } 59 | 60 | /** 61 | * Returns an image descriptor for the image file at the given 62 | * plug-in relative path 63 | * 64 | * @param path the path 65 | * @return the image descriptor 66 | */ 67 | public static ImageDescriptor getImageDescriptor(String path) { 68 | return imageDescriptorFromPlugin(PLUGIN_ID, path); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /org.clonedigger/src/org/clonedigger/ResultBrowser.java: -------------------------------------------------------------------------------- 1 | package org.clonedigger; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.net.URI; 8 | import java.net.URISyntaxException; 9 | import java.nio.MappedByteBuffer; 10 | import java.nio.channels.FileChannel; 11 | 12 | import org.eclipse.core.filesystem.EFS; 13 | import org.eclipse.core.filesystem.IFileStore; 14 | import org.eclipse.core.resources.IFile; 15 | import org.eclipse.core.resources.ResourcesPlugin; 16 | import org.eclipse.core.runtime.Path; 17 | import org.eclipse.jface.text.BadLocationException; 18 | import org.eclipse.jface.text.IDocument; 19 | import org.eclipse.swt.SWT; 20 | import org.eclipse.swt.browser.LocationEvent; 21 | import org.eclipse.swt.browser.LocationListener; 22 | import org.eclipse.swt.widgets.Composite; 23 | import org.eclipse.swt.widgets.FileDialog; 24 | import org.eclipse.swt.widgets.Shell; 25 | import org.eclipse.ui.IEditorInput; 26 | import org.eclipse.ui.IWorkbenchPage; 27 | import org.eclipse.ui.PartInitException; 28 | import org.eclipse.ui.PlatformUI; 29 | import org.eclipse.ui.ide.FileStoreEditorInput; 30 | import org.eclipse.ui.ide.IDE; 31 | import org.eclipse.ui.internal.browser.WebBrowserEditor; 32 | import org.eclipse.ui.part.FileEditorInput; 33 | import org.eclipse.ui.texteditor.ITextEditor; 34 | 35 | /** 36 | * Implementation of WebBrowser with support for "clone:" links. 37 | * Make a hook on location change event and navigate to editor. 38 | */ 39 | @SuppressWarnings("restriction") 40 | public class ResultBrowser extends WebBrowserEditor { 41 | 42 | private class CloneLocation implements LocationListener 43 | { 44 | 45 | public void changed(LocationEvent event) {} 46 | 47 | public void changing(LocationEvent event) 48 | { 49 | boolean WINDOWS = java.io.File.separatorChar == '\\'; 50 | 51 | if(event.location.startsWith("clone:")) 52 | { 53 | event.doit = false; 54 | try 55 | { 56 | String [] args = event.location.split("clone://|\\?|&"); 57 | 58 | //patch on strange browsersupport behavior on links with "\" character 59 | args[1] = args[1].replaceAll("/+$", ""); 60 | if(WINDOWS) args[1] = args[1].replaceAll("/", "\\\\"); 61 | 62 | IWorkbenchPage page = PlatformUI.getWorkbench() 63 | .getActiveWorkbenchWindow().getActivePage(); 64 | 65 | IFile file = ResourcesPlugin.getWorkspace().getRoot(). 66 | getFileForLocation(Path.fromOSString(args[1])); 67 | 68 | IEditorInput editInput = null; 69 | 70 | if(file == null) 71 | { 72 | // Process external files, files that arent present in workspace for some reasons. 73 | IFileStore fileStore = EFS.getLocalFileSystem().getStore( 74 | new URI("file:/" + args[1].replaceAll("^/+", "").replaceAll("\\\\", "/"))); 75 | editInput = new FileStoreEditorInput(fileStore); 76 | } 77 | else 78 | { 79 | editInput = new FileEditorInput(file); 80 | } 81 | 82 | ITextEditor editor = 83 | (ITextEditor)IDE.openEditor(page, editInput, 84 | IDE.getEditorDescriptor(args[1]).getId(), true); 85 | //"org.python.pydev.editor.PythonEditor", true); 86 | IDocument doc = editor.getDocumentProvider().getDocument(editInput); 87 | 88 | try 89 | { 90 | int start = doc.getLineInformation(Integer.parseInt(args[2])).getOffset(); 91 | int end = doc.getLineInformation(Integer.parseInt(args[3]) + 1).getOffset(); 92 | editor.setHighlightRange(start, end-start, true); 93 | } 94 | catch (BadLocationException e) { 95 | Activator.log(e); 96 | } 97 | } 98 | catch (PartInitException e) { 99 | Activator.log(e); 100 | } catch (URISyntaxException e) { 101 | Activator.log(e); 102 | } 103 | } 104 | 105 | if(event.location.startsWith("http:")) event.doit = false; 106 | 107 | if(event.location.startsWith(System.getProperty("java.io.tmpdir")) || 108 | event.location.startsWith("file:")) 109 | { 110 | String src = event.location; 111 | if(src.startsWith("file:")) 112 | { 113 | src = src.replaceAll("^file:", ""); 114 | src = src.replaceAll("^/+", ""); 115 | if(!WINDOWS) src = "/" + src; 116 | } 117 | 118 | event.doit = false; 119 | Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(); 120 | //SaveAsDialog dialog = new SaveAsDialog(shell); 121 | FileDialog dialog = new FileDialog(shell, SWT.SAVE); 122 | String[] exts = {"*.html"}; 123 | dialog.setFilterExtensions(exts); 124 | String dest = dialog.open(); 125 | if(dest != null) 126 | //if(dialog.open() == Window.OK) 127 | { 128 | //String dest = dialog.getResult().toOSString(); 129 | 130 | //ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(dest)). 131 | 132 | //dest = ResourcesPlugin.getPlugin().find(new Path(dest)).getPath(); 133 | //if(WINDOWS) dest = dest.replaceAll("^/+", ""); 134 | 135 | try { 136 | copy(new File(src), new File(dest)); 137 | } catch (IOException e) { 138 | Activator.log(e); 139 | } 140 | } 141 | } 142 | } 143 | } 144 | 145 | public static void copy(File source, File dest) throws IOException { 146 | FileChannel in = null, out = null; 147 | try { 148 | in = new FileInputStream(source).getChannel(); 149 | out = new FileOutputStream(dest).getChannel(); 150 | 151 | long size = in.size(); 152 | MappedByteBuffer buf = in.map(FileChannel.MapMode.READ_ONLY, 0, size); 153 | 154 | out.write(buf); 155 | 156 | } finally { 157 | if (in != null) in.close(); 158 | if (out != null) out.close(); 159 | } 160 | } 161 | 162 | public ResultBrowser() { 163 | } 164 | 165 | @Override 166 | public void createPartControl(Composite parent) { 167 | super.createPartControl(parent); 168 | if(webBrowser == null || webBrowser.getBrowser() == null) 169 | Activator.log(new Exception("No Browser support found")); 170 | webBrowser.getBrowser().addLocationListener(new CloneLocation()); 171 | } 172 | 173 | } 174 | 175 | 176 | -------------------------------------------------------------------------------- /org.clonedigger/src/org/clonedigger/actions/UpdateAction.java: -------------------------------------------------------------------------------- 1 | package org.clonedigger.actions; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | 6 | import org.clonedigger.Activator; 7 | import org.eclipse.core.runtime.FileLocator; 8 | import org.eclipse.core.runtime.Platform; 9 | import org.eclipse.jface.action.IAction; 10 | import org.eclipse.jface.dialogs.MessageDialog; 11 | import org.eclipse.jface.viewers.ISelection; 12 | import org.eclipse.ui.IWorkbenchWindow; 13 | import org.eclipse.ui.IWorkbenchWindowActionDelegate; 14 | import org.osgi.framework.Bundle; 15 | 16 | /** 17 | * Implementation of Update CloneDigger action. 18 | */ 19 | public class UpdateAction implements IWorkbenchWindowActionDelegate 20 | { 21 | boolean WINDOWS = java.io.File.separatorChar == '\\'; 22 | 23 | public UpdateAction() { 24 | } 25 | 26 | public void dispose() { 27 | } 28 | 29 | public void init(IWorkbenchWindow window) { 30 | } 31 | 32 | /** 33 | * Recursively delete directory. 34 | * @param f 35 | * @throws java.io.IOException 36 | */ 37 | private void delrec(File f) throws java.io.IOException { 38 | if (f.isDirectory()) { 39 | File[] fs=f.listFiles(); 40 | for (int i=0;i