From 6f3cbfeed92ef3fabb91622eb58c6ffe5c63289b Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Tue, 15 Jan 2013 15:54:30 +0000 Subject: Add scripts/edit-morph.py This allows programmatic edits of certain kinds to morphologies, to minimise the need for manual editing. --- scripts/edit-morph | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100755 scripts/edit-morph (limited to 'scripts') diff --git a/scripts/edit-morph b/scripts/edit-morph new file mode 100755 index 00000000..116b9681 --- /dev/null +++ b/scripts/edit-morph @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# Copyright (C) 2013 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +import cliapp +import os +import re + +import morphlib + +class EditMorph(cliapp.Application): + '''Tools for performing set operations on large morphologies''' + + def add_settings(self): + self.settings.boolean(['no-git-update'], + 'do not update the cached git repositories ' + 'automatically') + + def load_morphology(self, file_name, expected_kind = None): + with open(file_name) as f: + text = f.read() + try: + morphology = morphlib.morph2.Morphology(text) + except ValueError as e: + raise morphlib.Error("Error parsing %s: %s" % + (file_name, str(e))) + + if expected_kind is not None and morphology['kind'] != expected_kind: + raise morphlib.Error("Expected: a %s morphology" % expected_kind) + + return morphology + + + def cmd_remove_chunk(self, args): + '''Removes from STRATUM all reference of CHUNK''' + + if len(args) != 2: + raise cliapp.AppException("remove-chunk expects a morphology file " + "name and a chunk name") + + file_name = args[0] + chunk_name = args[1] + morphology = self.load_morphology(file_name, expected_kind = 'stratum') + + component_count = 0 + build_depends_count = 0 + new_chunks = morphology['chunks'] + for info in morphology['chunks']: + if info['name'] == chunk_name: + new_chunks.remove(info) + component_count += 1 + elif chunk_name in info['build-depends']: + info['build-depends'].remove(chunk_name) + build_depends_count += 1 + morphology._dict['chunks'] = new_chunks + + with morphlib.savefile.SaveFile(file_name, 'w') as f: + morphology.write_to_file(f) + + print "Removed: %i chunk(s) and %i build depend(s)." % \ + (component_count, build_depends_count) + + def cmd_sort(self, args): + """Sort STRATUM""" + + if len(args) != 1: + raise cliapp.AppException("sort expects a morphology file name") + + file_name = args[0] + morphology = self.load_morphology(file_name, expected_kind='stratum') + + for chunk in morphology['chunks']: + chunk['build-depends'].sort() + + morphology._dict['chunks'] = self.sort_chunks(morphology['chunks']) + + with morphlib.savefile.SaveFile(file_name, 'w') as f: + morphology.write_to_file(f) + + def sort_chunks(self, chunks_list): + """Sort stratum chunks + + The order is something like alphabetical reverse dependency order. + Chunks on which nothing depends are sorted at the bottom. + + The algorithm used is a simple-minded recursive sort. + """ + + chunk_dict = {} + for chunk in chunks_list: + chunk_dict[chunk['name']] = chunk + + reverse_deps_dict = {} + for chunk_name in chunk_dict.keys(): + chunk = chunk_dict[chunk_name] + for dep in chunk['build-depends']: + if dep not in reverse_deps_dict: + reverse_deps_dict[dep] = [chunk_name] + else: + reverse_deps_dict[dep].append(chunk_name) + + sort_order = list(chunk_dict.keys()) + sort_order.sort(key=unicode.lower) + + result = [] + satisfied_list = [] + repeat_count = 0 + while len(sort_order) > 0: + postponed_list = [] + + # Move any chunk into the result order that has all its + # dependencies satisfied in the result already. + for chunk_name in sort_order: + deps_satisfied = True + + chunk = chunk_dict[chunk_name] + for dep in chunk['build-depends']: + if dep not in satisfied_list: + deps_satisfied = False + if dep not in sort_order: + raise cliapp.AppException( + 'Invalid build-dependency for %s: %s' + % (chunk['name'], dep)) + break + + if deps_satisfied: + result.append(chunk) + satisfied_list.append(chunk_name) + else: + postponed_list.append(chunk_name) + + if len(postponed_list) == len(sort_order): + # This is not the smartest algorithm possible (but it works!) + repeat_count += 1 + if repeat_count > 10: + raise cliapp.AppException('Stuck in loop while sorting') + + assert(len(postponed_list) + len(result) == len(chunk_dict.keys())) + sort_order = postponed_list + + # Move chunks which are not build-depends of other chunks to the end. + targets = [c for c in chunk_dict.keys() if c not in reverse_deps_dict] + targets.sort(key=unicode.lower) + for chunk_name in targets: + result.remove(chunk_dict[chunk_name]) + result.append(chunk_dict[chunk_name]) + + return result + +EditMorph().run() -- cgit v1.2.1 From 42829e9d9aee1592cbd5391cdb30ab24f43370d1 Mon Sep 17 00:00:00 2001 From: Sam Thursfield Date: Mon, 18 Feb 2013 12:36:48 +0000 Subject: scripts/edit-morph: Add to-yaml and to-json commands --- scripts/edit-morph | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'scripts') diff --git a/scripts/edit-morph b/scripts/edit-morph index 116b9681..244bbd61 100755 --- a/scripts/edit-morph +++ b/scripts/edit-morph @@ -90,6 +90,48 @@ class EditMorph(cliapp.Application): with morphlib.savefile.SaveFile(file_name, 'w') as f: morphology.write_to_file(f) + def cmd_to_json(self, args): + """Convert one or more FILES to JSON. + + Assumes a .yaml extension, which will be removed in the output file. + """ + + if len(args) == 0: + raise cliapp.AppException("to-json expects one or more filenames") + + for file_name in args: + try: + with open(file_name, 'r') as f: + text = f.read() + morphology = morphlib.morph2.Morphology(text) + + if not file_name.endswith('.yaml'): + raise morphlib.Error('file name does not end with .yaml') + out_file_name = file_name[:-len('.yaml')] + + with morphlib.savefile.SaveFile(out_file_name, 'w') as f: + morphology.update_text(text, f, convert_to='json') + except Exception as e: + print '%s: %s' % (file_name, e) + + def cmd_to_yaml(self, args): + """Convert one or more FILES to YAML. + + Adds a .yaml extension for each input file.""" + + if len(args) == 0: + raise cliapp.AppException("to-yaml expects one or more filenames") + + for file_name in args: + try: + with open(file_name, 'r') as f: + text = f.read() + morphology = morphlib.morph2.Morphology(text) + with morphlib.savefile.SaveFile(file_name + '.yaml', 'w') as f: + morphology.update_text(text, f, convert_to='yaml') + except Exception as e: + print '%s: %s' % (file_name, e) + def sort_chunks(self, chunks_list): """Sort stratum chunks -- cgit v1.2.1