diff --git a/src/Tools/fcinfo b/src/Tools/fcinfo index 4e1ae74823..01a6d3e601 100755 --- a/src/Tools/fcinfo +++ b/src/Tools/fcinfo @@ -27,44 +27,74 @@ __title__="FreeCAD File info utility" __author__ = "Yorik van Havre" __url__ = ["http://www.freecadweb.org"] -__doc__ = '''This utility prints information about a given FreeCAD file (*.FCStd) -on screen, including document properties, number of included objects -and object sizes. +__doc__ = ''' +This utility prints information about a given FreeCAD file (*.FCStd) +on screen, including document properties, number of included objects, +object sizes and properties and values -It can be used as a textconv tool for git diff by configuring your git folder as follows: - 1) add to .gitattributes: - *.fcstd diff=fcinfo - 2) add to .git/config (or .gitconfig for user-wide): - [diff "fcinfo"] - textconv = /path/to/fcinfo +Usage: -Usage: fcinfo myfile.FCStd''' + fcinfo [options] myfile.FCStd + +Options: + + -h, --help: Prints this help text + -s, --short: Do not print all the properties contents of objects + -vs --veryshort: Only prints the document info, not objects info + +Git usage: + + This script can be used as a textconv tool for git diff by + configuring your git folder as follows: + + 1) add to .gitattributes: + *.fcstd diff=fcinfo + + 2) add to .git/config (or ~/.gitconfig for user-wide): + [diff "fcinfo"] + textconv = /path/to/fcinfo + + With this, when committing a .FCStd file with Git, + 'git diff' will show you the difference between the two + texts obtained by fcinfo + +''' import sys, zipfile, xml.sax, os, hashlib + + class FreeCADFileHandler(xml.sax.ContentHandler): - def __init__(self,zfile): + + + def __init__(self, zfile, short = 0): # short 0=normal, 1=short, 2=veryshort + xml.sax.ContentHandler.__init__(self) self.zfile = zfile self.obj = None self.prop = None self.count = "0" self.contents = {} + self.short = short def startElement(self, tag, attributes): + if tag == "Document": self.obj = tag + self.contents = {} self.contents["ProgramVersion"] = attributes["ProgramVersion"] self.contents["FileVersion"] = attributes["FileVersion"] + elif tag == "Object": - if not (attributes["name"] in self.contents): - self.contents[attributes["name"]] = "" - if "type" in attributes: - self.contents[attributes["name"]] += attributes["type"] - self.obj = attributes["name"] + if ("name" in attributes): + name = self.clean(attributes["name"]) + self.obj = name + if ("type" in attributes): + self.contents[name] = attributes["type"] + elif tag == "Part": if self.obj: s = self.zfile.read(attributes["file"]).__sizeof__() @@ -74,54 +104,98 @@ class FreeCADFileHandler(xml.sax.ContentHandler): s = str(s/1048576)+"M" else: s = str(s/1024)+"K" + self.contents[self.obj] += " (" + s + ")" + elif tag == "Property": self.prop = attributes["name"] - elif tag in ["String","Uuid"]: - if (self.obj == "Document") and self.prop: - self.contents[self.prop] = attributes["value"] + + elif tag in ["String","Uuid","Float","Integer","Bool","Link"]: + if self.prop and ("value" in attributes): + if self.obj == "Document": + self.contents[self.prop] = attributes["value"] + elif self.short == 0: + if tag == "Float": + self.contents[self.obj+"00000000::"+self.prop] = str(float(attributes["value"])) + else: + self.contents[self.obj+"00000000::"+self.prop] = attributes["value"] + elif tag == "Objects": self.count = attributes["Count"] self.obj = None + + # Print all the contents of the document properties items = self.contents.items() items.sort() - for key,val in items: - print (" " + key.encode("utf-8").strip() + " : " + val.encode("utf-8").strip()) + for key,value in items: + key = self.clean(key) + value = self.clean(value) + print(" " + key + " : " + value) + print(" Objects: ("+self.count+")") self.contents = {} - print (" Objects: ("+self.count+")") - - def endElement(self,tag): - if tag == "Document": - if self.contents: - items = self.contents.items() - items.sort() - for key,val in items: - print (" " + key + " : " + val) + + def endElement(self, tag): + + if (tag == "Document") and (self.short != 2): + items = self.contents.items() + items.sort() + for key,value in items: + key = self.clean(key) + if "00000000::" in key: + key = " "+key.split("00000000::")[1] + value = self.clean(value) + if value: + print(" " + key + " : " + value) + + def clean(self,value): + + value = value.strip() + if sys.version_info.major < 3: + value = value.encode("utf8") + return value if __name__ == '__main__': - if len(sys.argv) != 2: - print __doc__ - sys.exit(1) + if len(sys.argv) < 2: + print(__doc__) + sys.exit() - zfile=zipfile.ZipFile(sys.argv[1]) - files=zfile.namelist() + if ("-h" in sys.argv[1:]) or ("--help" in sys.argv[1:]): + print(__doc__) + sys.exit() - if files[0] != "Document.xml": + if not sys.argv[-1].lower().endswith(".fcstd"): + print(__doc__) + sys.exit() + + if ("-vs" in sys.argv[1:]) or ("--veryshort" in sys.argv[1:]): + short = 2 + elif ("-s" in sys.argv[1:]) or ("--short" in sys.argv[1:]): + short = 1 + else: + short = 0 + + if ("-g" in sys.argv[1:]) or ("--gui" in sys.argv[1:]): + gui = True + else: + gui = False + + zfile = zipfile.ZipFile(sys.argv[-1]) + + if not "Document.xml" in zfile.namelist(): sys.exit(1) doc = zfile.read("Document.xml") - s = os.path.getsize(sys.argv[1]) + s = os.path.getsize(sys.argv[-1]) if s < 1024: s = str(s)+"B" elif s > 1048576: s = str(s/1048576)+"M" else: s = str(s/1024)+"K" - print("Document: "+sys.argv[1]+" ("+s+")") - print (" SHA1: "+str(hashlib.sha1(open(sys.argv[1],'rb').read()).hexdigest())) - xml.sax.parseString(doc,FreeCADFileHandler(zfile)) - + print("Document: "+sys.argv[-1]+" ("+s+")") + print(" SHA1: "+str(hashlib.sha1(open(sys.argv[-1],'rb').read()).hexdigest())) + xml.sax.parseString(doc,FreeCADFileHandler(zfile,short))