PK!APaapackagr/__init__.py__version__ = '0.1.0' from packagr.packagr import application def run(): application.run()PK!packagr/commands/__init__.pyPK!1,̍eepackagr/commands/admin.pyfrom packagr.commands.base import Command import os import toml import subprocess class ConfigureClient(Command): """ Configure the CLI for your Packagr account configure {hash-id? : TYour Packagr account hash ID} {email? : Your packagr email address} {password? : Your packagr password} """ def handle(self): """ Creates a packagr config file at the root directory TODO: Need to update this to actually validate the hash_id and api_access_key before setting these values """ hash_id: str = self.argument('hash-id') email: str = self.argument('email') password: str = self.argument('password') config_path = os.path.expanduser('~') content = { 'url': f'https://api.packagr.app/{hash_id}/', 'email': email, 'hash-id': hash_id, 'password': password } with open(os.path.join(config_path, 'packagr_conf.toml'), 'w') as f: f.write(toml.dumps(content)) self.line('Successfully updated config file') class SetValue(Command): """ Adds a configuration variable to your project config set {key? : The property to update} {value? : The new value} """ def handle(self): key, value = self.argument('key'), self.argument('value') config = self.get_package_config() if config: try: assert not isinstance(config.get(key), list) except AssertionError: new_type = type(value) if not self.confirm(f'You are about to replace an array with a {new_type.__name__}. Continue?', False, '(?i)^(y|j)'): return self.update_config(config, **{key: value}) self.line(f'Successfully added key "{key}" with value "{value}"') class AddValue(Command): """ Appends a value to an existing array in the config add {key? : The property to update} {value? : The new value} """ def handle(self): key = self.argument('key') value = self.argument('value') config = self.get_package_config() if not config: return if self.append(config, key, value): self.line(f'Successfully added key "{key}" with value "{value}"') class InstallCommand(Command): """ Installs a package and updates the config install {packages* : The packages to install} {--i|ignore-errors : Continue to the next file even if errors are encountered} """ def handle(self): packages = self.argument('packages') ignore_errors = self.option('ignore-errors') config = self.get_global_config() url = f'https://{config["email"]}:{config["password"]}@api.packagr.app/{config["hash-id"]}/' for package in packages: status = subprocess.call(['pip', 'install', package, '--extra-index-url', url, '-q']) if status == 0: config = self.get_package_config() if config: self.append(config, 'install_requires', package) self.line(f'Installed package {package} and added it to the config') else: self.line(f'Error installing package {package}.') if not ignore_errors: self.line('Stopping process') return class UninstallCommand(Command): """ Uninstalls a package and removes it from the config uninstall {packages* : The packages to uninstall} {--i|ignore-errors : Continue to the next file even if errors are encountered} {--y|skip-prompts : Skip uninstall prompts} """ def handle(self): packages = self.argument('packages') ignore_errors = self.option('ignore-errors') skip_prompts = self.option('skip-prompts') config = self.get_package_config() for package in packages: commands = ['pip', 'uninstall', package,] if skip_prompts: commands.append('-y') status = subprocess.call(commands) if status == 0: removed = self.remove(config, 'install_requires', package) if not removed: return self.line(f'Successfully uninstalled {package}') else: self.line(f'Error uninstalling package {package}.') if not ignore_errors: self.line('Stopping process') return class BumpVersion(Command): """ Increases the version number of a package, e.g. 1.0.0 > 1.0.1, assuming that semver is used bump {version? : The new version number} {--a|major : Bumps the major version e.g. 1.0.0 > 2.0.0} {--i|minor : Bumps the minor version e.g. 1.0.0 > 1.1.0} """ def handle(self): config = self.get_package_config() if not config: return version = config.get('version', '0.1.0') version_opt = self.argument('version') major_opt, minor_opt = self.option('major'), self.option('minor') if version_opt: if major_opt or minor_opt: self.line('' 'Cannot use the version argument with either the --minor or --major arguments' '') return new_version = version_opt else: try: major, minor, bugfix = version.split('.') except ValueError: self.line('Cannot automatically bump version because this package does not appear to ' 'use Semver. Use `packagr bump ` instead') return if major_opt or minor_opt: if major_opt: major = int(major) + 1 if minor_opt: minor = int(minor) + 1 elif not version_opt: bugfix = int(bugfix) + 1 new_version = f'{major}.{minor}.{bugfix}' self.update_config(config, version=new_version) self.line(f'Updated version to {new_version}') class CreatePackage(Command): """ Creates a new Packagr config file init {name? : The name of the package - default to the current folder name if not provided} {--o|overwrite : Overwrite existing without prompt} """ def handle(self): """ Creates a file called `packagr.toml` in the current directory Checks if file exists first, prompts to replace """ name = self.argument('name') if not name: name = os.path.split(os.getcwd())[-1] overwrite = self.option('overwrite') template = { 'name': name, 'version': '0.1.0', 'packages': [name] } if not os.path.exists(name): os.makedirs(name) if os.path.exists('packagr.toml') and not overwrite: if not self.confirm('A package already exists at this location. Overwrite?', False, '(?i)^(y|j)'): return self.write_package_content(template) response = 'Created config file `packagr.toml`' self.line(response) PK!ȎH H packagr/commands/base.pyfrom cleo import Command as BaseCommand from packagr.utilities import get_package_config, write_package_content from typing import Any import os class Command(BaseCommand): def check_configuration(self): """ Check that a global config has been set with the `packagr configure` command TODO: implement this """ def get_global_config(self): """ Returns the content of the global config file """ return self.get_package_config(path=os.path.expanduser('~/packagr_conf.toml')) def get_package_config(self, path: str = 'packagr.toml'): config = get_package_config(path=path) if not config: self.line('' 'Unable to perform this action because no package exists at the current location. ' 'Run `packagr create` first' '') return config @staticmethod def write_package_content(config: dict, path: str = 'packagr.toml') -> None: write_package_content(config, path=path) def update_config(self, config, path: str = 'packagr.toml', **changes): for key, value in changes.items(): config[key] = value self.write_package_content(config, path=path) def append(self, config: dict, key: str, value: Any, path: str = 'packagr.toml') -> True: """ Adds a value to an array, if it isn't already in there """ existing = config.get(key, []) try: assert isinstance(existing, list) except AssertionError: self.line(f'Cannot add to value {key} because it is not an array') return if value not in existing: existing.append(value) self.update_config(config, **{key: existing}, path=path) return True def remove(self, config: dict, key: str, value: Any, path: str = 'packagr.toml') -> True: array = config.get(key, []) try: assert isinstance(array, list) except AssertionError: self.line(f'Cannot remove item because the property is not an arrary') return try: array.remove(value) except ValueError: return self.update_config(config, **{key: array}, path=path) return True PK!=5w w packagr/commands/packaging.pyfrom packagr.commands.base import Command from distutils.core import setup from packagr.utilities import get_package_config import os import requests import setuptools # DO NOT REMOVE THIS - IT IS IMPORTANT, EVEN THOUGH IT APPEARS TO NOT BE USED class CreatePackage(Command): """ Creates sdist wheel packages package {--w|no-wheel : Don't create a wheel package} {--s|no-sdist : Don't create an sdist package} """ def create_config(self, formats): config = get_package_config() output = { 'script_name': 'setup.py', 'script_args': formats + ['clean', '--all',] } for key, value in config.items(): output[key] = value return output def handle(self): formats: list = ['bdist_wheel', 'sdist'] if self.option('no-wheel'): formats.remove('bdist_wheel') if self.option('no-sdist'): formats.remove('sdist') if not formats: self.line('No formats to build!') return config = self.create_config(formats) setup(**config) self.line('Package built') class UploadPackage(Command): """ Uploads built packages to Packagr upload {--i|ignore-errors : Continue to the next file even if errors are encountered} """ def handle(self): self.check_configuration() config = self.get_global_config() package_config = self.get_package_config() ignore_errors = self.option('ignore-errors') upload_count = 0 for root, dirs, files in os.walk('dist'): if len(files) == 0: self.line('Nothing to upload. Run `packagr build` first to build a package') return for file in files: self.line(f'Attempting to upload file {file} to Packagr') files = {'content': (file, open(os.path.join(root, file), 'rb'))} headers = {} response = requests.post( config['url'], auth=(config['email'], config['password']), data={'name': package_config['name'], 'version': package_config['version']}, files=files, headers=headers ) try: assert response.status_code == 201 self.line(f'File {file} uploaded successfully') upload_count += 1 except AssertionError: if ignore_errors: self.line(f'Package failed to upload. Status code: {response.status_code}' f'\nSkipping to the next file...') else: self.line(f'Package failed to upload. Status code: {response.status_code}') return if upload_count == 0: self.line('No files uploaded') else: self.line(f'Uploaded {upload_count} files successfully') PK!N=packagr/packagr.py#!/usr/bin/env python3 from cleo import Application from packagr.commands import admin, packaging application = Application() # admin application.add(admin.CreatePackage()) application.add(admin.ConfigureClient()) application.add(admin.SetValue()) application.add(admin.AddValue()) application.add(admin.InstallCommand()) application.add(admin.UninstallCommand()) application.add(admin.BumpVersion()) # package application.add(packaging.CreatePackage()) application.add(packaging.UploadPackage()) def run(): application.run()PK!7packagr/utilities.pyimport toml def get_package_config(path: str = 'packagr.toml') -> dict: """ Returns the content of the package config file as a dict """ with open(path, 'r') as f: return toml.loads(f.read()) def write_package_content(config: dict, path: str = 'packagr.toml') -> None: """ Writes a given dict to the package config file """ with open(path, 'w') as f: f.write(toml.dumps(config)) PK!H!K#',packagr_cli-0.1.1.dist-info/entry_points.txtN+I/N.,()*HLNL/VEy\\PK!HڽTU!packagr_cli-0.1.1.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HhY B$packagr_cli-0.1.1.dist-info/METADATAYmo8_Ad?l%izb8lpضW,`EKF$!)Ɏ;p@F93yJz9Nv!+٨dy+v^:>Xoiw L<y-VƊ[n8ʛqu~~dvT\wqӺ'r՝GMUv\gVff7Mp)߈5>?o~!ƏhM_q^UNzvioQ3EoIF%:I3a:  IWA7]g,y YfKN) @aVI'V}[d.Rx͵`\C%Y6(e+ 6A{;-(t O^B{]{mQΝRȂ"n(DiomB;88Uw܈ҮMЇ<=Sު,邪J\n q+qI; ~[uCtl{y+z\nFrė|;mj|v )b-k!2)V0ۜdVʪcg`% p!;3AFX՘;hU*'n5q;ey>5P:D)o`#xq( "FXJ*@6% -dUj كhRJUq`m ~kEBW k9׭;(W,Kӷ~F2Hu [ *LokzVsַ _dJ*;=zÅt`?ң]P-gL&M-By%>@Z %+ndN7 wĂt3=OHntaJd1] 4O(d9*Plᘫ*#+ :I!(}l$'.0 A;URf tҹR+מ;|92u5p`̑VHDtPUbv~x(9y0#SMKU}f Odl{gvU8S17-K l6gU@,{lhKggTt$á]<8Ojra3p)F.= {i!TzZ#p'I6)e<@M_G< l;E4}O!J/d#݋ K9 |F4i<,Ns$&A$em "j VVPJk%Gz]C}Y@mtDŽ ioHdY6L0K'@CoLiryMi{H'BLŞ-O9$PnB xCdO*Ggٲl t[*mS n- ֕pa Ĺ )u fN~պ$A<_VJ-JD17>#ه66օuѵ=EAQuM~cDD|ʏʝ<G6l}1Y@N||{Ճ1혐]6{K,N\6ho\0h N drِkǍ'_d&N~QfluB8@L}#~?]xJvSaltNk XL:J;"^\pe_&2r ̅5@hU6"y.T^31 %1 FcӂT\$Kmש'eA)P4-H2O,N5U̲0OpâA%i(0EAOW],a(s]M(3g# +Cj:c׎7W)< TuD}DMikíUŘ15B*8t 1W#`PLף1k̍de4g㕆XO"t.i[3&5xriA{GAB0ek꘼ˁK凫mt6rlLw=2#,E&LI!\JҔAY15bdtloY ُ _)KE<ȣy(J=ލ;+Ȼ`\j'WK(@Um.Ǹ?iV+,i 0<4J*U?PBi"-5gռsM싧b /ӞtV%ğFDXJݿPK!H&)h"packagr_cli-0.1.1.dist-info/RECORD}n@{v} Y~Fc)%C]ڷ0%𵞉1+K@rhЬ|f?c:Qe\+K)ʤɉu&mWvDήH~N3n 6].FI'PcSmv1=^#.Wwa10"8'PG[1o مgĔ"&b>R³ {Ie〗n DU=N cE޴\COTAƙ6~ k$3ة@dRl"x_9q=Ya&7P8'Z/{i.,+֭GjEpUx1I&]O\ea]^P>,IU?BX( rEmHLjq mR{!6q^z#X) nȑ_L'xH'1s5LV$tJsԏֺ 7PK!APaapackagr/__init__.pyPK!packagr/commands/__init__.pyPK!1,̍eepackagr/commands/admin.pyPK!ȎH H hpackagr/commands/base.pyPK!=5w w 'packagr/commands/packaging.pyPK!N=4packagr/packagr.pyPK!76packagr/utilities.pyPK!H!K#',8packagr_cli-0.1.1.dist-info/entry_points.txtPK!HڽTU!.9packagr_cli-0.1.1.dist-info/WHEELPK!HhY B$9packagr_cli-0.1.1.dist-info/METADATAPK!H&)h"\Epackagr_cli-0.1.1.dist-info/RECORDPK 0G