def run(self, args): os.environ["PATH"] = "{}:{}".format( os.path.join(self.sdk_path(args), "arm-cs-tools", "bin"), os.environ["PATH"] ) cmdLine = self.waf_path(args) + " " + self.waf_cmds retval = subprocess.call(cmdLine, shell=True) # If an error occurred, we need to do some sleuthing to determine a # cause. This allows the caller to post more useful information to # analytics. We normally don't capture stdout and stderr using Poepn() # because you lose the nice color coding produced when the command # outputs to a terminal directly. # # But, if an error occurs, let's run it again capturing the output # so we can determine the cause if retval: cmdArgs = cmdLine.split() try: cmdObj = create_sh_cmd_obj(cmdArgs[0]) output = cmdObj(*cmdArgs[1:]) stderr = output.stderr except sh.ErrorReturnCode as e: stderr = e.stderr # Look for common problems if "Could not determine the compiler version" in stderr: raise NoCompilerException elif "region `APP' overflowed" in stderr: raise AppTooBigException else: raise BuildErrorException elif args.command == "build": # No error building. Send up app memory usage and resource usage # up to analytics # Read in the appinfo.json to get the list of resources try: appInfo = json.load(open("appinfo.json")) self._send_memory_usage(args, appInfo) self._send_resource_usage(args, appInfo) self._send_line_counts(args, appInfo) hasJS = os.path.exists(os.path.join("src", "js")) PblAnalytics.code_has_java_script_evt(uuid=appInfo["uuid"], hasJS=hasJS) except Exception as e: logging.error("Exception occurred collecting app analytics: " "%s" % str(e)) logging.debug(traceback.format_exc()) return 0
def _send_line_counts(self, args, appInfo): """ Send app line counts up to analytics Parameters: -------------------------------------------------------------------- args: the args passed to the run() method appInfo: the applications appInfo """ c_line_count = 0 js_line_count = 0 if os.path.exists("src"): c_line_count += self._count_lines("src", [".h", ".c"]) js_line_count += self._count_lines("src", [".js"]) PblAnalytics.code_line_count_evt(uuid=appInfo["uuid"], c_line_count=c_line_count, js_line_count=js_line_count)
def _send_resource_usage(self, args, appInfo): """ Send app resource usage up to analytics Parameters: -------------------------------------------------------------------- args: the args passed to the run() method appInfo: the applications appInfo """ # Collect the number and total size of each class of resource: resCounts = {"raw": 0, "image": 0, "font": 0} resSizes = {"raw": 0, "image": 0, "font": 0} for resDict in appInfo["resources"]["media"]: if resDict["type"] in ["png", "png-trans"]: resource_type = "image" elif resDict["type"] in ["font"]: resource_type = "font" elif resDict["type"] in ["raw"]: resource_type = "raw" else: raise RuntimeError("Unsupported resource type %s" % (resDict["type"])) # Look for the generated blob in the build/resource directory. # As far as we can tell, the generated blob always starts with # the original filename and adds an extension to it, or (for # fonts), a name and extension. (dirName, fileName) = os.path.split(resDict["file"]) dirToSearch = os.path.join("build", "resources", dirName) found = False size = 0 for name in os.listdir(dirToSearch): if name.startswith(fileName): size = os.path.getsize(os.path.join(dirToSearch, name)) found = True break if not found: raise RuntimeError("Could not find generated resource " "corresponding to %s." % (resDict["file"])) resCounts[resource_type] += 1 resSizes[resource_type] += size # Send the stats now PblAnalytics.res_sizes_evt(uuid=appInfo["uuid"], resCounts=resCounts, resSizes=resSizes)
def _send_memory_usage(self, args, appInfo): """ Send app memory usage to analytics Parameters: -------------------------------------------------------------------- args: the args passed to the run() method appInfo: the applications appInfo """ cmdName = "arm_none_eabi_size" cmdArgs = [os.path.join("build", "pebble-app.elf")] try: output = sh.arm_none_eabi_size(*cmdArgs) (textSize, dataSize, bssSize) = [int(x) for x in output.stdout.splitlines()[1].split()[:3]] sizeDict = {"text": textSize, "data": dataSize, "bss": bssSize} PblAnalytics.code_size_evt(uuid=appInfo["uuid"], segSizes=sizeDict) except sh.ErrorReturnCode as e: logging.error( "command %s %s failed. stdout: %s, stderr: %s" % (cmdName, " ".join(cmdArgs), e.stdout, e.stderr) ) except sh.CommandNotFound as e: logging.error("The command %s could not be found. Could not " "collect memory usage analytics." % e.message)
def run_action(self, action, args): # Find the extension that was called command = [x for x in self.commands if x.name == args.command][0] try: retval = command.run(args) if retval: PblAnalytics.cmd_fail_evt(args.command, 'unknown error') else: cmdName = args.command if cmdName == 'install' and args.logs is True: cmdName = 'install --logs' PblAnalytics.cmd_success_evt(cmdName) return retval except libpebble.PebbleError as e: PblAnalytics.cmd_fail_evt(args.command, 'pebble error') if args.debug: raise e else: logging.error(e) return 1 except ConfigurationException as e: PblAnalytics.cmd_fail_evt(args.command, 'configuration error') logging.error(e) return 1 except InvalidProjectException as e: PblAnalytics.cmd_fail_evt(args.command, 'invalid project') logging.error("This command must be run from a Pebble project " "directory") return 1 except OutdatedProjectException as e: PblAnalytics.cmd_fail_evt(args.command, 'outdated project') logging.error("The Pebble project directory is using an outdated " "version of the SDK!") logging.error("Try running `pebble convert-project` to update the " "project") return 1 except NoCompilerException as e: PblAnalytics.missing_tools_evt() logging.error("The compiler/linker tools could not be found. " "Ensure that the arm-cs-tools directory is present " "in the Pebble SDK directory (%s)" % PblCommand().sdk_path(args)) return 1 except BuildErrorException as e: PblAnalytics.cmd_fail_evt(args.command, 'compilation error') logging.error("A compilation error occurred") return 1 except AppTooBigException as e: PblAnalytics.cmd_fail_evt(args.command, 'application too big') logging.error("The built application is too big") return 1 except Exception as e: PblAnalytics.cmd_fail_evt(args.command, 'unhandled exception: %s' % str(e)) logging.error(str(e)) return 1
import pebble.PblAnalytics as PblAnalytics # Catch any missing python dependencies so we can send an event to analytics try: import pebble as libpebble from pebble.PblProjectCreator import (PblProjectCreator, InvalidProjectException, OutdatedProjectException) from pebble.PblProjectConverter import PblProjectConverter from pebble.PblBuildCommand import PblBuildCommand, PblCleanCommand from pebble.LibPebblesCommand import * except Exception as e: logging.basicConfig(format='[%(levelname)-8s] %(message)s', level=logging.DEBUG) PblAnalytics.missing_python_dependency_evt(str(e)) raise class PbSDKShell: commands = [] def __init__(self): self.commands.append(PblProjectCreator()) self.commands.append(PblProjectConverter()) self.commands.append(PblBuildCommand()) self.commands.append(PblCleanCommand()) self.commands.append(PblInstallCommand()) self.commands.append(PblInstallFWCommand()) self.commands.append(PblPingCommand()) self.commands.append(PblListCommand())
import pebble.PblAnalytics as PblAnalytics # Catch any missing python dependencies so we can send an event to analytics try: import pebble as libpebble from pebble.PblProjectCreator import (PblProjectCreator, InvalidProjectException, OutdatedProjectException) from pebble.PblProjectConverter import PblProjectConverter from pebble.PblBuildCommand import PblBuildCommand, PblCleanCommand from pebble.LibPebblesCommand import * except Exception as e: logging.basicConfig(format='[%(levelname)-8s] %(message)s', level = logging.DEBUG) PblAnalytics.missing_python_dependency_evt(str(e)) raise class PbSDKShell: commands = [] def __init__(self): self.commands.append(PblProjectCreator()) self.commands.append(PblProjectConverter()) self.commands.append(PblBuildCommand()) self.commands.append(PblCleanCommand()) self.commands.append(PblInstallCommand()) self.commands.append(PblInstallFWCommand()) self.commands.append(PblPingCommand()) self.commands.append(PblListCommand()) self.commands.append(PblRemoteCommand())