Skip to content

Commit

Permalink
Merge branch 'pebble-packages'
Browse files Browse the repository at this point in the history
  • Loading branch information
Katharine committed Jun 1, 2016
2 parents 9878624 + 39d5e1c commit e600aee
Show file tree
Hide file tree
Showing 8 changed files with 380 additions and 81 deletions.
2 changes: 1 addition & 1 deletion pebble_tool/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .commands import (install, logs, screenshot, timeline, emucontrol, ping, account, repl,
transcription_server, data_logging)
from .commands.sdk import create, emulator
from .commands.sdk.project import analyse_size, convert, debug
from .commands.sdk.project import package, analyse_size, convert, debug
from .exceptions import ToolError
from .sdk import sdk_version
from .util.analytics import wait_for_analytics, analytics_prompt
Expand Down
162 changes: 100 additions & 62 deletions pebble_tool/commands/sdk/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,83 +13,85 @@
from pebble_tool.util.analytics import post_event


def _copy_template(name, directory_list, appinfo_list, file_list, create_dir_list):
try:
project_path = name
project_name = os.path.split(project_path)[1]
project_root = os.path.join(os.getcwd(), project_path)
except OSError as e:
if e.errno == errno.EEXIST:
raise ToolError("A directory called '{}' already exists.".format(project_name))
raise

for directory in directory_list:
if os.path.exists(directory):
template_path = directory
break
else:
raise ToolError("Can't create that sort of project with the current SDK.")

for appinfo_path in appinfo_list:
appinfo_path = os.path.join(template_path, appinfo_path)
if os.path.exists(appinfo_path):
file_list.append((appinfo_path, os.path.join(project_root, os.path.basename(appinfo_path))))
break
else:
raise ToolError("Couldn't find an appinfo-like file.")

for file_path in file_list:
if isinstance(file_path, basestring):
origin_path = os.path.join(template_path, file_path)
target_path = os.path.join(project_root, file_path)
else:
origin_path = os.path.join(template_path, file_path[0])
target_path = os.path.join(project_root, file_path[1])

if os.path.exists(origin_path):
try:
os.makedirs(os.path.dirname(target_path))
except OSError as e:
if e.errno != errno.EEXIST:
raise
with open(origin_path) as f:
template = Template(f.read())
with open(target_path, 'w') as f:
f.write(template.substitute(uuid=str(uuid4()),
project_name=project_name,
display_name=project_name,
sdk_version=SDK_VERSION))


class NewProjectCommand(SDKCommand):
"""Creates a new pebble project with the given name in a new directory."""
command = 'new-project'

def __call__(self, args):
super(NewProjectCommand, self).__call__(args)

# User can give a path to a new project dir
project_path = args.name
project_name = os.path.split(project_path)[1]
project_root = os.path.join(os.getcwd(), project_path)

project_src = os.path.join(project_root, "src")

# Create directories
try:
os.makedirs(project_root)
os.makedirs(os.path.join(project_root, "resources"))
os.makedirs(project_src)
except OSError as e:
if e.errno == errno.EEXIST:
raise ToolError("A directory called '{}' already exists.".format(args.name))
raise

project_template_path = os.path.join(self.get_sdk_path(), 'pebble', 'common', 'templates')
if not os.path.exists(project_template_path):
project_template_path = os.path.join(os.path.dirname(__file__), '..', '..', 'sdk', 'templates')

# Create main .c file
if args.simple:
default_main = os.path.join(project_template_path, 'simple.c')
else:
default_main = os.path.join(project_template_path, 'main.c')
copy2(default_main, os.path.join(project_src, "{}.c".format(project_name)))

# Add appinfo.json file
with open(os.path.join(project_template_path, 'appinfo.json')) as f:
appinfo = Template(f.read())

with open(os.path.join(project_root, "appinfo.json"), "w") as f:
f.write(appinfo.substitute(uuid=str(uuid4()), project_name=project_name, sdk_version=SDK_VERSION))

# Add .gitignore file
copy2(os.path.join(project_template_path, 'gitignore'), os.path.join(project_root, '.gitignore'))

# Add javascript files if applicable
sdk2 = self.sdk == "2.9" or (self.sdk is None and sdk_version() == "2.9")

template_paths = [
os.path.join(self.get_sdk_path(), 'pebble', 'common', 'templates', 'app'),
os.path.join(self.get_sdk_path(), 'pebble', 'common', 'templates'),
os.path.join(os.path.dirname(__file__), '..', '..', 'sdk', 'templates'),
]
file_list = [
('gitignore', '.gitignore'),
('simple.c' if args.simple else 'main.c', 'src/{}.c'.format(project_name)),
('wscript_sdk2' if sdk2 else 'wscript', 'wscript')
]
if args.javascript:
project_js_src = os.path.join(project_src, "js")
os.makedirs(project_js_src)

try:
copy2(os.path.join(project_template_path, 'app.js'),
os.path.join(project_js_src, 'app.js'))
except IOError as e:
if e.errno != errno.ENOENT:
raise e
copy2(os.path.join(project_template_path, 'pebble-js-app.js'),
os.path.join(project_js_src, 'pebble-js-app.js'))

# Add background worker files if applicable
file_list.extend([('app.js', 'src/js/app.js'), ('pebble-js-app.js', 'src/js/pebble-js-app.js')])
if args.worker:
project_worker_src = os.path.join(project_root, "worker_src")
os.makedirs(project_worker_src)
# Add simple source file
copy2(os.path.join(project_template_path, 'worker.c'),
os.path.join(project_worker_src, "{}_worker.c".format(project_name)))

# Add wscript file
if self.sdk == "2.9" or (self.sdk is None and sdk_version() == "2.9"):
copy2(os.path.join(project_template_path, 'wscript_sdk2'), os.path.join(project_root, "wscript"))
else:
copy2(os.path.join(project_template_path, 'wscript'), os.path.join(project_root, "wscript"))
file_list.append(('worker.c', 'worker/{}_worker.c'.format(project_name)))

_copy_template(args.name, template_paths, ['package.json', 'appinfo.json'], file_list, ['resources'])

post_event("sdk_create_project", javascript=args.javascript, worker=args.worker)
print("Created new project {}".format(args.name))


@classmethod
def add_parser(cls, parser):
parser = super(NewProjectCommand, cls).add_parser(parser)
Expand All @@ -98,3 +100,39 @@ def add_parser(cls, parser):
parser.add_argument("--javascript", action="store_true", help="Generate a JavaScript file.")
parser.add_argument("--worker", action="store_true", help="Generate a background worker.")
return parser


class NewPackageCommand(SDKCommand):
"""Creates a new pebble package (not app or watchface) with the given name in a new directory."""
command = 'new-package'

def __call__(self, args):
super(NewPackageCommand, self).__call__(args)

package_path = args.name
package_name = os.path.split(package_path)[1]

template_paths = [
os.path.join(self.get_sdk_path(), 'pebble', 'common', 'templates', 'lib'),
]
file_list = [
('gitignore', '.gitignore'),
('lib.c', 'src/c/{}.c'.format(package_name)),
('lib.h', 'include/{}.h'.format(package_name)),
'wscript',
]
dir_list = ['src/resources']
if args.javascript:
file_list.append(('lib.js', 'src/js/index.js'))

_copy_template(args.name, template_paths, ['package.json'], file_list, dir_list)

post_event("sdk_create_package", javascript=args.javascript)
print("Created new package {}".format(args.name))

@classmethod
def add_parser(cls, parser):
parser = super(NewPackageCommand, cls).add_parser(parser)
parser.add_argument("name", help="Name of the package you want to create")
parser.add_argument("--javascript", action="store_true", help="Include a js directory.")
return parser
8 changes: 8 additions & 0 deletions pebble_tool/commands/sdk/project/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from pebble_tool.exceptions import BuildError
from pebble_tool.util.analytics import post_event
import pebble_tool.util.npm as npm
from pebble_tool.commands.sdk.project import SDKProjectCommand


Expand All @@ -18,6 +19,13 @@ class BuildCommand(SDKProjectCommand):
def __call__(self, args):
super(BuildCommand, self).__call__(args)
start_time = time.time()
if len(self.project.dependencies) > 0:
post_event('app_build_with_npm_deps')
try:
npm.invoke_npm(["install"])
except subprocess.CalledProcessError:
post_event("app_build_failed_npm")
raise BuildError("npm failed.")
try:
waf = list(args.args)
try:
Expand Down
58 changes: 55 additions & 3 deletions pebble_tool/commands/sdk/project/convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,74 @@
from shutil import copy2

from pebble_tool.commands.sdk.project import SDKProjectCommand
from pebble_tool.sdk.project import PebbleProject, OutdatedProjectException
from pebble_tool.exceptions import OutdatedProjectException, ToolError
from pebble_tool.sdk.project import NpmProject
from pebble_tool.sdk import pebble_platforms


class PblProjectConverter(SDKProjectCommand):
"""Structurally converts an SDK 2 project to an SDK 3 project. Code changes may still be required."""
"""Converts an appinfo project from SDK 2 or SDK 3 to a modern package.json project."""
command = 'convert-project'

def __call__(self, args):
try:
super(PblProjectConverter, self).__call__(args)
print("No conversion required")
if not isinstance(self.project, NpmProject):
self._convert_to_npm()
print("Converted to package.json format.")
else:
print("No conversion required")
except OutdatedProjectException:
self._convert_project()
self._convert_to_npm()
print("Project successfully converted!")

def _convert_to_npm(self):
new_info = {
'name': self.project.short_name,
'author': self.project.company_name,
'version': self.project.version + '.0',
'pebble': {
'sdkVersion': self.project.sdk_version,
'targetPlatforms': self.project.target_platforms,
'enableMultiJS': self.project.enable_multi_js,
'capabilities': self.project.capabilities,
'projectType': self.project.project_type,
'displayName': self.project.long_name,
'uuid': str(self.project.uuid),
'watchapp': {
'watchface': self.project.is_watchface,
'hiddenApp': self.project.is_hidden,
'onlyShownOnCommunication': self.project.is_shown_only_on_communication,
},
'resources': self.project.resources,
'messageKeys': self.project.message_keys,
}
}
if os.path.exists('package.json'):
with open('package.json') as f:
try:
new_info.update(json.load(f))
except ValueError:
raise ToolError("An invalid package.json already exists; conversion aborted.")
copy2('package.json', 'package.json~')
print("A package.json already exists. It has been backed up to package.json~.")
with open('package.json', 'w') as f:
json.dump(new_info, f, indent=2, separators=(',', ': '))
os.unlink('appinfo.json')

self._ignore_npm()

def _ignore_npm(self):
if os.path.exists('.gitignore'):
with open('.gitignore') as f:
content = f.read()
if 'node_modules' in content:
return

with open('.gitignore', 'a') as f:
f.write("\nnode_modules/\n")

def _convert_project(self):
project_root = os.getcwd()
project_template_path = os.path.join(self.get_sdk_path(), 'pebble', 'common', 'templates')
Expand Down
48 changes: 48 additions & 0 deletions pebble_tool/commands/sdk/project/package.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# encoding: utf-8
from __future__ import absolute_import, print_function

import subprocess

from . import SDKProjectCommand
from pebble_tool.exceptions import ToolError
import pebble_tool.util.npm as npm

__author__ = "katharine"


class PackageManager(SDKProjectCommand):
"""Manages npm packages."""
command = 'package'
has_subcommands = True

def __call__(self, args):
super(PackageManager, self).__call__(args)
args.sub_func(args)

@classmethod
def add_parser(cls, parser):
parser = super(PackageManager, cls).add_parser(parser)
subparsers = parser.add_subparsers(title="subcommand")

install_parser = subparsers.add_parser("install", help="Installs the given package.")
install_parser.add_argument('package', nargs='?', help="npm package to install.")
install_parser.set_defaults(sub_func=cls.do_install)

uninstall_parser = subparsers.add_parser("uninstall", help="Uninstalls the given package.")
uninstall_parser.add_argument('package', help="package to uninstall.")
uninstall_parser.set_defaults(sub_func=cls.do_uninstall)

return parser

@classmethod
def do_install(cls, args):
try:
npm.invoke_npm(["install", "--save", "--ignore-scripts", args.package])
npm.invoke_npm(["dedupe"])
npm.sanity_check()
except subprocess.CalledProcessError:
raise ToolError()

@classmethod
def do_uninstall(cls, args):
npm.invoke_npm(["uninstall", "--save", "--ignore-scripts", args.package])
Loading

0 comments on commit e600aee

Please sign in to comment.