mirror of
https://gitlab.gnome.org/jwestman/blueprint-compiler.git
synced 2025-05-04 15:59:08 -04:00
`blueprint-compiler port` interactively ports a project to blueprint. It will create the subproject wrap file, add it to .gitignore, decompile your GtkBuilder XML files, emit code to copy and paste into your meson.build file, and update POTFILES.in. It can't quite handle all of the features the forward compiler can, so it will skip those files.
141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
# main.py
|
|
#
|
|
# Copyright 2021 James Westman <james@jwestman.net>
|
|
#
|
|
# This file 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 3 of the
|
|
# License, or (at your option) any later version.
|
|
#
|
|
# This file 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 program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
|
|
import argparse, json, os, sys
|
|
|
|
from .errors import PrintableError, report_bug, MultipleErrors
|
|
from .lsp import LanguageServer
|
|
from . import parser, tokenizer, decompiler, interactive_port
|
|
from .utils import Colors
|
|
from .xml_emitter import XmlEmitter
|
|
|
|
|
|
VERSION = "0.1.0"
|
|
|
|
|
|
class BlueprintApp:
|
|
def main(self):
|
|
self.parser = argparse.ArgumentParser()
|
|
self.subparsers = self.parser.add_subparsers(metavar="command")
|
|
self.parser.set_defaults(func=self.cmd_help)
|
|
|
|
compile = self.add_subcommand("compile", "Compile blueprint files", self.cmd_compile)
|
|
compile.add_argument("--output", dest="output", default="-")
|
|
compile.add_argument("input", metavar="filename", default=sys.stdin, type=argparse.FileType('r'))
|
|
|
|
batch_compile = self.add_subcommand("batch-compile", "Compile many blueprint files at once", self.cmd_batch_compile)
|
|
batch_compile.add_argument("output_dir", metavar="output-dir")
|
|
batch_compile.add_argument("input_dir", metavar="input-dir")
|
|
batch_compile.add_argument("inputs", nargs="+", metavar="filenames", default=sys.stdin, type=argparse.FileType('r'))
|
|
|
|
port = self.add_subcommand("port", "Interactive porting tool", self.cmd_port)
|
|
|
|
lsp = self.add_subcommand("lsp", "Run the language server (for internal use by IDEs)", self.cmd_lsp)
|
|
lsp.add_argument("--logfile", dest="logfile", default=None, type=argparse.FileType('a'))
|
|
|
|
self.add_subcommand("help", "Show this message", self.cmd_help)
|
|
|
|
try:
|
|
opts = self.parser.parse_args()
|
|
opts.func(opts)
|
|
except SystemExit as e:
|
|
raise e
|
|
except KeyboardInterrupt:
|
|
print(f"\n\n{Colors.RED}{Colors.BOLD}Interrupted.{Colors.CLEAR}")
|
|
except EOFError:
|
|
print(f"\n\n{Colors.RED}{Colors.BOLD}Interrupted.{Colors.CLEAR}")
|
|
except:
|
|
report_bug()
|
|
|
|
|
|
def add_subcommand(self, name, help, func):
|
|
parser = self.subparsers.add_parser(name, help=help)
|
|
parser.set_defaults(func=func)
|
|
return parser
|
|
|
|
|
|
def cmd_help(self, opts):
|
|
self.parser.print_help()
|
|
|
|
|
|
def cmd_compile(self, opts):
|
|
data = opts.input.read()
|
|
try:
|
|
xml = self._compile(data)
|
|
|
|
if opts.output == "-":
|
|
print(xml)
|
|
else:
|
|
with open(opts.output, "w") as file:
|
|
file.write(xml)
|
|
except PrintableError as e:
|
|
e.pretty_print(opts.input.name, data)
|
|
sys.exit(1)
|
|
|
|
|
|
def cmd_batch_compile(self, opts):
|
|
for file in opts.inputs:
|
|
data = file.read()
|
|
|
|
try:
|
|
if not os.path.commonpath([file.name, opts.input_dir]):
|
|
print(f"{Colors.RED}{Colors.BOLD}error: input file '{file.name}' is not in input directory '{opts.input_dir}'{Colors.CLEAR}")
|
|
sys.exit(1)
|
|
|
|
xml = self._compile(data)
|
|
|
|
path = os.path.join(
|
|
opts.output_dir,
|
|
os.path.relpath(
|
|
os.path.splitext(file.name)[0] + ".ui",
|
|
opts.input_dir
|
|
)
|
|
)
|
|
os.makedirs(os.path.dirname(path), exist_ok=True)
|
|
with open(path, "w") as file:
|
|
file.write(xml)
|
|
except PrintableError as e:
|
|
e.pretty_print(file.name, data)
|
|
sys.exit(1)
|
|
|
|
|
|
def cmd_lsp(self, opts):
|
|
langserv = LanguageServer(opts.logfile)
|
|
langserv.run()
|
|
|
|
|
|
def cmd_port(self, opts):
|
|
interactive_port.run(opts)
|
|
|
|
|
|
def _compile(self, data: str) -> str:
|
|
tokens = tokenizer.tokenize(data)
|
|
ast, errors = parser.parse(tokens)
|
|
|
|
if errors:
|
|
raise errors
|
|
if len(ast.errors):
|
|
raise MultipleErrors(ast.errors)
|
|
|
|
return ast.generate()
|
|
|
|
|
|
def main():
|
|
BlueprintApp().main()
|