On Thu, Apr 10, 2008 at 3:57 PM, Martin Langhoff <[EMAIL PROTECTED]> wrote: > Attached you'll find a trivial script to concat-and-sort various lease > files. This makes life easier for regional teams that deal with > various shipments. > > Usage: > > cat-leases.pl */lease.sig > all_leases.sig
Ok, the script I posted initially didn't work because the leases file is in Canonical JSON, not any plain old JSON thing. So here's a python version using the Canonical JSON libs. I have also attached the json.py file, which I stole from bitfrost. If you have bitfrost anywhere in your python path, you won't need this additional json.py . The usage is the same as above, except that a significant "l" changes to a "y". cheers, m -- [EMAIL PROTECTED] [EMAIL PROTECTED] -- School Server Architect - ask interesting questions - don't get distracted with shiny stuff - working code first - http://wiki.laptop.org/go/User:Martinlanghoff
#!/usr/bin/python # # Usage: # # cat-leases.pl */lease.sig > all_leases.sig # # cat-leases will concatenate and sort the JSON-encoded # activation leases (for OLPC XOs of the XO-1 series). # # # NOTE: the json we import here is actually # "Canonical JSON" reader/writer from the # bitfrost/util directory. # # # Blame: Martin Langhoff <[EMAIL PROTECTED]> # License: GPL v2 # # if Bitfrost's json.py is in the PYTHONPATH import json # if Bitfrost is in the PYTHONPATH #import bitfrost.util.json as json import sys data = {} # note - we skip the zeroth position # of argv which has $0 for n in range(1,len(sys.argv)): fn = sys.argv[n] file = open(fn, 'r') fcontent = file.read() file.close() # read the data and pull the dict out of the nested # structure newdata = json.read(fcontent) newdata = newdata.pop() data.update(newdata) ordereddata = {} for k in sorted(newdata.keys()): ordereddata[k] = newdata[k] json.write_to_file(sys.stdout, [1, ordereddata])
#!/usr/bin/python2.5 """Canonical JSON reader/writer. See http://wiki.laptop.org/go/Canonical_JSON for specification. >>> _selfTest() All tests passed. """ import re, types ## json.py implements a JSON (http://json.org) reader and writer. ## Copyright (C) 2005 Patrick D. Logan ## Contact mailto:[EMAIL PROTECTED] ## ## This library is free software; you can redistribute it and/or ## modify it under the terms of the GNU Lesser General Public ## License as published by the Free Software Foundation; either ## version 2.1 of the License, or (at your option) any later version. ## ## This library is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## Lesser General Public License for more details. ## ## You should have received a copy of the GNU Lesser General Public ## License along with this library; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## HACKED TO PIECES by C. Scott Ananian, 2007. ## to support "canonical JSON" format (and only that!) class _StringGenerator(object): def __init__(self, string): self.string = string self.index = 0 # first unread character def peek(self): i = self.index if i < len(self.string): return self.string[i] else: return None def next(self): if self.index < len(self.string): c = self.string[self.index] self.index += 1 return c else: raise StopIteration def read_re(self, regex, group=0): m = regex.match(self.string, self.index) if m is None: raise ReadException("Trying to read %s: '%s'" % (regex, self.string[self.index:])) self.index = m.end() return m.group(group) def all(self): return self.string class WriteException(Exception): pass class ReadException(Exception): pass class CJsonReader(object): hex_digits = {'a': 10,'b': 11,'c': 12,'d': 13,'e': 14,'f':15} def read(self, s): self._generator = _StringGenerator(s) result = self._read() if self._generator.peek() is not None: raise ReadException("String incompletely read.") return result def _read(self): peek = self._generator.peek() if peek is None: raise ReadException("Nothing to read: '%s'" % self._generator.all()) if peek == '{': return self._readObject() elif peek == '[': return self._readArray() elif peek == '"': return self._readString() elif peek == '-' or peek.isdigit(): return self._readNumber() elif peek == 't': return self._readTrue() elif peek == 'f': return self._readFalse() elif peek == 'n': return self._readNull() else: raise ReadException("Input is not valid canonical JSON: '%s'" % self._generator.all()) __true_regex=re.compile(r'true') def _readTrue(self): self._generator.read_re(CJsonReader.__true_regex) return True __false_regex=re.compile(r'false') def _readFalse(self): self._generator.read_re(CJsonReader.__false_regex) return False __null_regex=re.compile(r'null') def _readNull(self): self._generator.read_re(CJsonReader.__null_regex) return None def _assertNext(self, ch, target): if self._generator.next() != ch: raise ReadException("Trying to read %s: '%s'" % (target, self._generator.all())) __num_regex=re.compile(r'0|(-?[1-9][0-9]*)') def _readNumber(self): result = self._generator.read_re(CJsonReader.__num_regex) peek = self._generator.peek() if peek is not None and peek.isdigit(): raise ReadException("Leading zeros not allowed") try: return int(result) except ValueError: raise ReadException("Not a valid JSON number: '%s'" % result) __str1_regex=re.compile(r'"((?:[^"\\]+|\\["\\])*)"') __str2_regex=re.compile(r'\\(["\\])') def _readString(self): result = self._generator.read_re(CJsonReader.__str1_regex, 1) result = CJsonReader.__str2_regex.sub(r'\1', result) return result def _hexDigitToInt(self, ch): try: result = self.hex_digits[ch] except KeyError: try: result = int(ch) except ValueError: raise ReadException("The character %s is not a lowercase hex digit." % ch) return result def _readArray(self): result = [] assert self._generator.next() == '[' done = self._generator.peek() == ']' while not done: item = self._read() result.append(item) done = self._generator.peek() == ']' if not done: ch = self._generator.next() if ch != ",": raise ReadException("Not a valid JSON array: '%s' due to: '%s'" % (self._generator.all(), ch)) assert ']' == self._generator.next() return result def _readObject(self): lastkey = None result = {} assert self._generator.next() == '{' done = self._generator.peek() == '}' while not done: key = self._read() if type(key) is not types.StringType and type(key) is not types.UnicodeType: raise ReadException("Not a valid JSON object key (should be a string): %s" % key) if lastkey is not None and key <= lastkey: raise ReadException("Keys are not sorted (not canonical form)") else: lastkey = key ch = self._generator.next() if ch != ":": raise ReadException("Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch)) val = self._read() result[key] = val done = self._generator.peek() == '}' if not done: ch = self._generator.next() if ch != ",": raise ReadException("Not a valid JSON object: '%s' due to: '%s'" % (self._generator.all(), ch)) assert self._generator.next() == "}" return result class CJsonWriter(object): def write(self, obj): results = [] self._append = lambda s: results.append(s) self._write(obj) return "".join(results) def write_to_file(self, f, obj): self._append = lambda s: f.write(s) self._write(obj) __str_regex=re.compile(r'([^"\\]+)|["\\]') def _write(self, obj): ty = type(obj) if ty is types.DictType: n = len(obj) self._append("{") for k in sorted(obj.keys()): if not (type(k) is types.StringType or type(k) is types.UnicodeType): raise WriteException("Keys must be strings.") self._write(k) self._append(":") self._write(obj[k]) n = n - 1 if n > 0: self._append(",") self._append("}") elif ty is types.ListType or ty is types.TupleType: n = len(obj) self._append("[") for item in obj: self._write(item) n = n - 1 if n > 0: self._append(",") self._append("]") elif ty is types.StringType or ty is types.UnicodeType: self._append('"') if ty is types.UnicodeType: try: import unicodedata obj = unicodedata.normalize("NFD", obj).encode('utf-8') except ImportError: raise WriteException("Package unicodedata not found: no support for writing unicode string: %s" % obj) for m in CJsonWriter.__str_regex.finditer(obj): c = m.group() if c[0] == "\\" or c[0] == '"': self._append("\\"+c[0]) else: self._append(c) # no escaping needed for this piece self._append('"') elif ty is types.IntType or ty is types.LongType: self._append(str(obj)) elif obj is True: self._append("true") elif obj is False: self._append("false") elif obj is None: self._append("null") else: raise WriteException("Cannot write in canonical JSON: %s" % repr(obj)) def write(obj): """Return a string representing `obj` encoded using canonical JSON.""" return CJsonWriter().write(obj) def write_to_file(f, obj): """Write the canonical JSON encoding of `obj` to the file-like object `f`.""" return CJsonWriter().write_to_file(f, obj) def read(s): """Read a canonical-JSON-encoded string `s` and return its value as an object.""" return CJsonReader().read(s) ## self-test code def _selfTest(): """Self-test code.""" def expectReadFail(s): try: read(s) raise AssertionError("Expected read of %s to fail." % s) except ReadException: pass # this is what should happen def expectWriteFail(o): try: s = write(o) raise AssertionError("Expected write to fail, but yielded %s." % s) except WriteException: pass # this is what should happen def expectWrite(obj, expect_str): assert write(obj) == expect_str def expectRead(s, result): expectWrite(read(s), write(result)) # okay, here are the tests expectReadFail('') expectRead('0', 0) expectRead('-1', -1) expectRead('10', 10) expectReadFail('01') expectReadFail('-0') expectReadFail('00') expectReadFail('0x00') expectWrite(-0, '0') expectWrite({'c':'d','a':'b'}, '{"a":"b","c":"d"}') expectRead('[0,1,2,3,4,5]',[0,1,2,3,4,5]) expectReadFail('{ }') expectReadFail('[ ]') expectReadFail('0 ') expectReadFail('[0,]') expectRead('"foo"','foo') expectRead('"foo\\"\'\\\\bar"', "foo\"\'\\bar") expectRead('"nin\xcc\x83a"', u'ni\xf1a') expectWrite('"', '"\\\""') expectReadFail('"\\u0000"') expectReadFail('"\\x1f"') expectReadFail('"""') # no floats allowed expectWriteFail(1.2) # only string keys allowed expectWriteFail({1:2}) expectRead('[1,"a",{},[30,null]]',[1,"a",{},[30,None]]) # don't try to normalize unnormalized UTF-8 # (from fig 4 of http://www.unicode.org/reports/tr15/) expectRead('"\xc5"', '\xc5') # not canonicalized expectRead('"\xf4"', '\xf4') # not canonicalized # but normalize unicode values written. expectWrite(u'\u00C5', '"A\xcc\x8a"') expectWrite(u'\u00F4', '"o\xcc\x82"') return "All tests passed." if __name__ == '__main__': print _selfTest()
_______________________________________________ Devel mailing list Devel@lists.laptop.org http://lists.laptop.org/listinfo/devel