PK!aD   dada/.DS_StoreBud1 cache_  @ @ @ @ __pycache__lsvCblobbplist00 JKLMNO_useRelativeDates_showIconPreviewWcolumns_calculateAllSizes_scrollPositionYXtextSize_scrollPositionXZsortColumnXiconSize_viewOptionsVersion $(-27<@E  WvisibleUwidthYascendingZidentifier , TnameUwidthYascendingWvisibleXubiquity# !# \dateModified!'[dateCreated *, aTsize / 1 s Tkind4 6d Ulabel9 ;K Wversion ? XcommentsBD^dateLastOpenedF!YdateAdded##@(#@Tname#@00BJ^py"$%&/023@IJKW`acdirsuv{ P __pycache__lsvpblobbplist00 GHIJKC_useRelativeDates_showIconPreviewWcolumns_calculateAllSizes_scrollPositionYXtextSize_scrollPositionXZsortColumnXiconSize_viewOptionsVersion  %*/49>BXcomments^dateLastOpened[dateCreatedTsizeUlabelTkindWversionTname\dateModified UindexUwidthYascendingWvisible, !"&'+, a 01 d 56 s :; K ?  C'  ##@(#@Tname#@00BJ^py  &,6>@CDENPRST]_abclnpqr{}L __pycache__vSrnlong E DSDB ` @ @ @Tname#@00BJ^py  &,6>@CDENPRST]_abclnpqr{}L __pycache__vSrnlongPK!dada/__init__.pyPK!rԲdada/config/base.tomledit-command = 'code' config-edit-command = 'nvim' browser = 'google chrome' pdf-viewer = 'skim' kind-keys = [ 'category' ] keys = [ 'title', 'shortcut', 'kind', 'development-url', # command 'build-command', 'serve-command', 'edit-command', # path 'path', 'code-path', 'web-path', 'staging-path', 'edit-path', ] PK!::dada/config/categories.toml[web] taskrunner = 'grunt' [document] taskrunner = 'make'PK!qS$[[dada/config/kinds.backup.toml[invoice] category = 'document' taskrunner = 'make' root = '/Users/dominic/business/invoices/open' [invoice.makefile] template = 'documents/invoice/makefile' path = 'makefile' [mkdocs] category = 'web' server = 'mkdocs serve' local_url = 'http://127.0.0.1:8000' [bolt] category = 'web' mamp = true taskrunner = 'grunt' [bolt.project_config] path = '.project.toml' template = 'misc/project/bolt.yml' [harp] category = 'web' local_url = 'http://localhost:9000' taskrunner = 'grunt' [harp.reset] path = 'public/styles/_reset.styl' template = 'web/stylus/_reset.styl' [harp.index] path = 'public/index.jade' template = 'web/jade/index.jade' [harp.gruntfile] path = 'gruntfile.coffee' template = 'web/harp/gruntfile.coffee' [harp.packagejson] path = 'package.json' template = 'web/harp/package.json' PK!dada/config/kinds2.backup.tomlPK!&>1>1dada/projects.pyfrom datetime import date from os import environ from pathlib import Path from shutil import copy, copytree from subprocess import run, Popen from typing import List import toml from click import secho, confirm, echo PROJECT_CONFIG_FILENAME = '.dadaproject.toml' APP_CONFIG_DIR = Path(__file__).parent / 'config' APP_BASE_CONFIG_PATH = APP_CONFIG_DIR / 'base.toml' APP_KINDS_CONFIG_PATH = APP_CONFIG_DIR / 'kinds.toml' APP_KINDS_DIR = Path(__file__).parent / 'kinds' USER_CONFIG_DIR = environ.get('$XDG_CONFIG_HOME', Path.home() / '.config' / 'dada') if not USER_CONFIG_DIR.exists(): USER_CONFIG_DIR.mkdir(parents=True) USER_BASE_CONFIG_PATH = USER_CONFIG_DIR / 'base.toml' if not USER_BASE_CONFIG_PATH.exists(): USER_BASE_CONFIG_PATH.touch() USER_KINDS_DIR = USER_CONFIG_DIR / 'kinds' TEMPLATES_PATH = '' #todo class BaseConfig: with APP_BASE_CONFIG_PATH.open() as f: base_config = toml.load(f) if USER_BASE_CONFIG_PATH.exists(): with USER_BASE_CONFIG_PATH.open() as f: user_base_config = toml.load(f) else: USER_BASE_CONFIG_PATH.touch() user_base_config = {} @classmethod def keys(cls): app_config_keys = list(cls.base_config) user_config_keys = list(cls.user_base_config) return app_config_keys + user_config_keys @classmethod def get(cls, key: str): if key in cls.user_base_config: return cls.user_base_config[key] elif key in cls.base_config: return cls.base_config[key] @classmethod def print(cls): for key in cls.keys(): print(f'{key}: {cls.get(key)}') class Project: store = {} ready = False @classmethod def init(cls): config_paths = Project.project_config_paths() for path in config_paths: Project.add_from_config_path(path) cls.ready = True @classmethod def project_config_paths(cls): if not BaseConfig.get('project-dirs'): print('Could not look for projects because no project directories are defined.') return [] config_paths = [] dirs = [Path(dir).expanduser() for dir in BaseConfig.get('project-dirs')] for dir in dirs: for config in dir.glob(f'*/{PROJECT_CONFIG_FILENAME}'): config_paths.append(config) return config_paths @staticmethod def local(): path = Path('.') / PROJECT_CONFIG_FILENAME with path.open() as f: dictionary = toml.load(f) return Project(dictionary, path=Path.cwd()) @classmethod def from_shortcut(cls, shortcut): if shortcut == 'local': return Project.local() else: return cls.store.get(shortcut, None) @classmethod def shortcuts(cls): return cls.store.keys() @classmethod def add_from_config_path(cls, config_path: Path): with config_path.open() as f: try: dictionary = toml.load(f) except Exception: print(f'Could not read config file {config_path}.') return project_path = config_path.parent project = Project(dictionary, project_path) shortcut = project.shortcut Project.store[shortcut] = project @classmethod def all(cls): return Project.store.values() @classmethod def from_path(cls, path: Path): with open(path / PROJECT_CONFIG_FILENAME) as f: dictionary = toml.load(f) return Project(dictionary, path=path) def __init__(self, config_dictionary: dict, path: Path): if not config_dictionary: print(f'Problem with reading project config from {path}') return else: self.config_dictionary = config_dictionary if 'kind' in config_dictionary: self.kind = Kind.get(config_dictionary['kind']) else: self.kind = 'undefined' self.path = path.absolute() self.config_path = self.path / PROJECT_CONFIG_FILENAME self.title = config_dictionary.get('title', None) if 'code-path' in config_dictionary: setattr(self, 'code_path', path / config_dictionary['code-path']) else: setattr(self, 'code_path', self.path) if 'web-path' in config_dictionary: setattr(self, 'web_path', path / config_dictionary['web-path']) else: setattr(self, 'web_path', self.path) # if 'live_path' in config_dictionary: # self.live_path = Path(config_dictionary['live_path']) def __getattr__(self, item): item = item.replace('_', '-') if item in self.config_dictionary: return self.config_dictionary[item] elif hasattr(self, 'kind') and hasattr(self.kind, item): return getattr(self.kind, item) elif BaseConfig.get(item): return BaseConfig.get(item) def build(self): Popen([self.build_command], cwd=self.code_path) # if self.taskrunner == 'grunt': # run(['dkill', 'grunt']) # todo # Popen(['grunt'], cwd=self.code_path) # # if self.taskrunner == 'make': # run(['make'], cwd=self.code_path) def serve(self): # if hasattr(self, 'mamp') and self.mamp: # run(['mamp', 'switch', self.web_path]) # # elif str(self.kind) == 'harp': # run(['dkill', 'harp']) # todo: change # Popen(['harp', 'server'], cwd=self.code_path) Popen(self.serve_command.split(' '), cwd=self.code_path) self.show_in_browser() def show_in_browser(self): run(['open', '-a', BaseConfig.get('browser'), self.development_url]) def open_document(self): run(['open', '-a', BaseConfig.get('pdf-viewer'), 'document.pdf'], cwd=self.code_path) def update_component(self, component: str): relative_path = self.kind.get_component_path(component) path = self.path / relative_path template_path = self.kind.get_template_path(component) if not path or confirm('Do you want to override existing files?'): copy(path, path.with_suffix('.backup' + path.suffix)) copy(template_path, path) # def update_template(self, component_type: str): # installed = self.get_component(component_type) # template = get_component_template(component_type, self.type) # if confirm(f'Do you want to override {template}?'): # project_type_config = Kind.from_string(self.type) # if component_type in project_type_config: # copy(template, template.with_suffix('.backup.coffee')) # copy(installed, template) def edit(self): if self.edit_command == 'code': workspaces = list(self.path.glob('*.code-workspace')) if workspaces: run([self.edit_command, workspaces[0]]) else: run([self.edit_command, self.code_path]) if self.edit_path: path = self.code_path / self.edit_path else: path = self.code_path run([self.edit_command, path]) def start(self): print_summary(self) self.edit() self.build() self.show_output() def show_output(self): if self.kind.category == 'web': self.serve() self.show_in_browser() elif self.kind.category == 'document': self.open_document() else: raise Exception('') class Kind: _store = {} ready = False @classmethod def init(cls): for kind_dir in USER_KINDS_DIR.iterdir(): key = kind_dir.name try: with open(kind_dir / 'config.toml') as f: config_dict = toml.load(f) except: continue kind = Kind(dictionary=config_dict, key=key) cls._store[key] = kind cls.ready = True # with USER_KINDS_CONFIG_PATH.open() as f: # try: # config = toml.load(f) # except Exception: # print_error(f'We could not read the config file {USER_KINDS_CONFIG_PATH}') # return # for title, kind_dictionary in config.items(): # kind = Kind(dictionary=kind_dictionary, title=title) # cls.store[title] = kind @staticmethod def get(key): return Kind._store.get(key, None) @classmethod def all(cls): return cls._store.values() def __init__(self, dictionary, key): if 'root' in dictionary: self.root = Path(dictionary['root']) self._dictionary = dictionary self.key = key if 'category' in dictionary: self.category = Category.get(dictionary['category']) self.template_directory = USER_KINDS_DIR / key / 'template' self.config_path = USER_KINDS_DIR / key / 'config.toml' def __getattr__(self, item): if item in self._dictionary: return self._dictionary[item] else: raise AttributeError def __str__(self): return self.key def print(self): print(self.__dict__) # def get_template_path(self, component: str) -> Path: # if component in self.dictionary: # return TEMPLATES_PATH / self.dictionary[component]['template'] # else: # print(f'No template defined for {component} in {self}') # exit() # todo def get_component_path(self, component: str) -> Path: if component in self.dictionary: return self.dictionary[component]['path'] else: print(f'No {component} defined for {self}') exit() class Category: _store = {} ready = False @classmethod def init(cls): with USER_BASE_CONFIG_PATH.open() as f: config = toml.load(f) categories_dict = config['category'] for key, category_dict in categories_dict.items(): cls._store[key] = Category(dictionary=category_dict, key=key) cls.ready = True @classmethod def all(cls): return cls._store.values() @classmethod def get(cls, key): if key in cls._store: return cls._store[key] else: raise KeyError def __init__(self, dictionary: dict, key: str): self._dictionary = dictionary self.key = key def __getattr__(self, item): if item in self._dictionary: return self._dictionary[item] else: raise AttributeError def __eq__(self, other): return str(self) == str(other) def __str__(self): return self.key def create_project(kind_key:str, title: str): kind = Kind.get(kind_key) root = Path('.') directory_name = title.replace(' ', '-') source = kind.template_directory destination = root / directory_name copytree(source, destination) save_project_config(path=destination / PROJECT_CONFIG_FILENAME, kind_key=kind.key, title=title) project = Project.from_path(destination) project.start() def save_project_config(path: Path, kind_key: str = None, title: str = None, shortcut: str = None): data = {} if kind_key: data['kind'] = kind_key if title: data['title'] = title if shortcut: data['shortcut'] = shortcut with path.open('w') as f: toml.dump(data, f) def print_error(string, color='red'): secho('==> Problem: ', fg=color, nl=False) echo(string) def print_summary(object, additional_keys: List[str]=None, primary_color='yellow'): secho('------------------------------------------------------------------------', fg=primary_color) if object.title: secho('title: ', nl=False, fg=primary_color) secho(object.title.upper(), bold=True) if additional_keys: keys = additional_keys + BaseConfig.get('keys') else: keys = BaseConfig.get('keys') for key in keys: if key in ['title']: continue key = key.replace('-', '_') if hasattr(object, key) and getattr(object, key): secho(f'{key.replace("_", "-")}: ', nl=False, fg=primary_color) echo(f'{getattr(object, key)}') secho('------------------------------------------------------------------------', fg=primary_color) for cls in (Category, Kind, Project): if not cls.ready: cls.init() PK!dada/scripts/__init__.pyPK!dada/scripts/dada.py#!/usr/bin/env python3 from pathlib import Path from subprocess import run import toml from click import echo, group, prompt, argument, option, secho, edit, style, Choice from dada import projects from dada.projects import Project, Kind, create_project, PROJECT_CONFIG_FILENAME, BaseConfig, print_summary, Category, \ save_project_config from pick import pick PRIMARY_COLOR = 'blue' @group() def cli(): pass @cli.group() def config(): pass @config.command() @argument('shortcut', required=False) def project(shortcut): local_config_path = Path('.', PROJECT_CONFIG_FILENAME) if shortcut or local_config_path.is_file(): project = get_project(shortcut) config_path = project.path / PROJECT_CONFIG_FILENAME edit_command = BaseConfig.get('config-edit-command') run([edit_command, config_path]) else: print(f'Creating new project config file {PROJECT_CONFIG_FILENAME}') converter = lambda kind: str(kind) kind_key = prompt(style('Kind', fg=PRIMARY_COLOR), type=Choice(Kind.all()), default=None, value_proc=converter) title = prompt('Title?') shortcut = prompt('Shortcut?') save_project_config(path=local_config_path, title=title, kind_key=kind_key, shortcut=shortcut) @config.command() def list(): BaseConfig.print() @config.command() @argument('key') def kind(key): kind = Kind.get(key) editor = BaseConfig.get('config-edit-command') run([editor, kind.config_path]) @cli.command() @argument('shortcut', required=False) def output(shortcut): project = get_project(shortcut) project.show_output() @cli.command() @argument('kind') @option('--title', prompt=True) def new(kind, title): create_project(kind_key=kind, title=title) @cli.command() @argument('key', required=False) def kinds(key): if key: kind = Kind.get(key) print_summary(kind) else: for kind in Kind.all(): print(kind) @cli.command() @argument('shortcut') def debug(shortcut): project = get_project(shortcut) print(project.__dict__) @cli.command() @argument('shortcut') def compile(shortcut): project = get_project(shortcut) project.build() @cli.command() @argument('shortcut', required=False) def serve(shortcut): project = get_project(shortcut) project.serve() @cli.command() @argument('shortcut', required=False) def edit(shortcut): get_project(shortcut).edit() # # @cli.command() @argument('shortcut', required=False) def start(shortcut): project = get_project(shortcut) project.start() @cli.command() @argument('shortcut') @argument('component') def update(shortcut, component): project = get_project(shortcut) secho('==> ', fg='red', nl=False) secho(f'Updating {component} of project {project.title}.', bold=True) project.update_component(component) # @cli.command() # @argument('component_type') # @pass_context # def upstream(context, component_type): # project = context.obj['project'] # project.update_template(component_type) @cli.command() @argument('shortcut', required=False) def info(shortcut): project = get_project(shortcut) print_summary(project) @cli.command() def init(): title = prompt(text='Title') shortcut = prompt(text='Shortcut') kind, _ = pick([kind.title for kind in Kind.all()], 'Please choose kind of project:') data = { 'title': title, 'shortcut': shortcut, 'kind': kind } with Path(projects.PROJECT_CONFIG_FILENAME).open('w') as f: toml.dump(data, f) @cli.group() def list(): pass @list.command() def projects(): for project in Project.all(): echo(f'{project.shortcut}\t{project.title}') @list.command() def categories(): for category in Category.all(): print(category) def get_project(shortcut): if shortcut: return Project.from_shortcut(shortcut) elif Project.local(): return Project.local() else: print(f'No project found.') exit() PK!HBG&.%dada-0.1.0.dist-info/entry_points.txtN+I/N.,()JILIzP!=*9' PK!YC..dada-0.1.0.dist-info/LICENSEMIT License Copyright (c) 2018 Dominic Looser Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.PK!HnHTUdada-0.1.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HNb|dada-0.1.0.dist-info/METADATAN0EA,1) m( 4~`;/a ľsgtgA"Fgl"fPP})ojk2P^^A@4ТDΌ1vF2GIX9ԶTBV`]ժxZFFK|CLS}iu(a;q:>aeB`D=d!$0u*{/~?"Fl=Kk=aeL鄢%.k9i~^p } dO[#vCA`T68hϝ8'}=WrXB9EavV'ÝqN]Ǽ "ehi&rEJ$%裁"9Gε}ߤp 'ZIn=:iS,T0-'؍ @/fiɴ1>1U&dada/projects.pyPK!Wdada/scripts/__init__.pyPK!Wdada/scripts/dada.pyPK!HBG&.%gdada-0.1.0.dist-info/entry_points.txtPK!YC..Zhdada-0.1.0.dist-info/LICENSEPK!HnHTUldada-0.1.0.dist-info/WHEELPK!HNb|Nmdada-0.1.0.dist-info/METADATAPK!H۩`/odada-0.1.0.dist-info/RECORDPKq