Source code for rattail.projects.handler

# -*- coding: utf-8; -*-
################################################################################
#
#  Rattail -- Retail Software Framework
#  Copyright © 2010-2023 Lance Edgar
#
#  This file is part of Rattail.
#
#  Rattail 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, either version 3 of the License, or (at your option) any later
#  version.
#
#  Rattail 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
#  Rattail.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Handler for Generating Projects
"""

import os
import shutil
import warnings
import zipfile
from collections import OrderedDict

from rattail.util import load_entry_points


[docs] class ProjectHandler(object): """ Base class for project handlers. """ def __init__(self, config): self.config = config self.app = self.config.get_app()
[docs] def get_all_project_generators(self): """ Returns an ``OrderedDict`` with all available project generators. """ generators = load_entry_points('rattail.projects') generators = sorted(generators.items(), key=lambda itm: itm[0]) return OrderedDict(generators)
[docs] def get_all_project_types(self): """ Returns the list of keys for *all* possible project types. """ warnings.warn("get_all_project_types() is deprecated; " "please use get_all_project_generators() instead", DeprecationWarning, stacklevel=2) return list(self.get_all_project_generators())
[docs] def get_supported_project_generators(self): """ Returns the list of "supported" project generators. """ return self.get_all_project_generators()
[docs] def get_supported_project_types(self): """ Returns the list of keys for "supported" project types. """ warnings.warn("get_supported_project_types() is deprecated; " "please use get_supported_project_generators() instead", DeprecationWarning, stacklevel=2) return list(self.get_supported_project_generators())
[docs] def get_project_generator(self, key, require=False): """ Returns a ``ProjectGenerator`` instance for the given key. If the key is not valid, returns ``None`` unless ``require=True`` in which case an error is raised. """ generators = self.get_all_project_generators() if key in generators: return generators[key](self.config) if require: raise RuntimeError("Project generator not found for: {}".format(key))
[docs] def get_storage_dir(self): """ Returns the path to root storage (output) dir for all generated projects. """ path = self.config.get('rattail', 'generated_projects.storage_dir') if path: return path return os.path.join(self.config.workdir(require=True), 'generated-projects')
[docs] def make_project_schema(self, key): """ Make and return a colander schema representing the context needed for generating a project for the given key. """ generator = self.get_project_generator(key, require=True) return generator.make_schema()
[docs] def generate_project(self, key, output=None, context=None, **kwargs): """ Generate source code for a new project, and return the path to the output folder. :param key: Key identifying which type of project to generate. :param output: Optional path to the output folder. If not specified, one will be determined automatically. :param context: Data dictionary with template context, appropriate for the project type. """ generator = self.get_project_generator(key) context = generator.normalize_context(context or {}) if not output: folder = context.get('folder', key) output = os.path.join(self.get_storage_dir(), folder) if os.path.exists(output): shutil.rmtree(output) os.makedirs(output) generator.generate_project(output, context) return output
[docs] def zip_output(self, output, zipped=None): """ Compress the given output folder and save as ZIP file. :param output: Path to the output folder. :param zipped: Optional path to the final ZIP file. If not specified, it will be the same path as ``output`` but with a ``.zip`` file extension. """ if not zipped: zipped = '{}.zip'.format(output) folder = os.path.basename(output) with zipfile.ZipFile(zipped, 'w', zipfile.ZIP_DEFLATED) as z: self.zipdir(z, output, folder) return zipped
def zipdir(self, zipf, path, folder): for root, dirs, files in os.walk(path): relative_root = os.path.join(folder, root[len(path)+1:]) for fname in files: zipf.write(os.path.join(root, fname), arcname=os.path.join(relative_root, fname))
[docs] class RattailProjectHandler(ProjectHandler): def __init__(self, *args, **kwargs): warnings.warn("RattailProjectHandler is deprecated; " "please just use ProjectHandler instead", DeprecationWarning, stacklevel=2) super(RattailProjectHandler, self).__init__(*args, **kwargs)