def command_create(): if os.path.exists(defaults.SRC_DIR): raise ForgeError( 'Source folder "%s" already exists, if you really want to create a new app you will need to remove it!' % defaults.SRC_DIR) questions = { 'description': 'Enter details for app', 'properties': { 'name': { 'type': 'string', 'title': 'App Name', 'description': 'This name is what your application will be called on devices. You can change it later through config.json.' } } } answers = cli.ask_question({'schema': questions}) if 'name' in answers and answers['name']: forge.settings['name'] = answers['name'] username = forge.settings['username'] app_uuid = str(uuid.uuid4().hex) app_name = forge.settings['name'] # generate app with open_file(path.join(config_dir, 'manifest.json')) as manifest_file: manifest = json.loads(manifest_file.read()) zipf = InMemoryZip() for item in manifest: initial_file = template_file( config_dir, item["path"], item["template"], ( ('${username}', username), ('${uuid}', app_uuid), ('${name}', app_name), ('${platform_version}', forge.settings['LAST_STABLE']), )) zipf.writestr(item["path"], initial_file) with zipfile.ZipFile(StringIO(zipf.read())) as myzip: myzip.extractall() LOG.info('App structure created. To proceed:') LOG.info('1) Put your code in the "%s" folder' % defaults.SRC_DIR) LOG.info('2) Run %s build to make a build' % ENTRY_POINT_NAME)
def command_create(): if os.path.exists(defaults.SRC_DIR): raise ForgeError('Source folder "%s" already exists, if you really want to create a new app you will need to remove it!' % defaults.SRC_DIR) questions = { 'description': 'Enter details for app', 'properties': { 'name': { 'type': 'string', 'title': 'App Name', 'description': 'This name is what your application will be called on devices. You can change it later through config.json.' } } } answers = cli.ask_question({ 'schema': questions }) if 'name' in answers and answers['name']: forge.settings['name'] = answers['name'] username = forge.settings['username'] app_uuid = str(uuid.uuid4().hex) app_name = forge.settings['name'] # generate app with open_file(path.join(config_dir, 'manifest.json')) as manifest_file: manifest = json.loads(manifest_file.read()) zipf = InMemoryZip() for item in manifest: initial_file = template_file(config_dir, item["path"], item["template"], ( ('${username}', username), ('${uuid}', app_uuid), ('${name}', app_name), ('${platform_version}', forge.settings['LAST_STABLE']), )) zipf.writestr(item["path"], initial_file) with zipfile.ZipFile(StringIO(zipf.read())) as myzip: myzip.extractall() LOG.info('App structure created. To proceed:') LOG.info('1) Put your code in the "%s" folder' % defaults.SRC_DIR) LOG.info('2) Run %s build to make a build' % ENTRY_POINT_NAME)
def _dispatch_command(command, other_args): """Runs our subcommand in a separate thread, and handles events emitted by it""" call = None task_thread = None try: other_other_args = handle_secondary_options(command, other_args) subcommand = COMMANDS[command] # setup enough stuff so the target function can communicate back using events call = async.Call( call_id=0, target=subcommand, args=(other_other_args, ), input=Queue.Queue(), output=Queue.Queue(), ) async.set_current_call(call, thread_local=True) # capture logging on any thread but this one and turn it into events handler = async.CallHandler(call) handler.setLevel(logging.DEBUG) current_thread = threading.current_thread().name filtered_handler = FilterHandler(handler, lambda r: r.threadName != current_thread) filtered_handler.setLevel(logging.DEBUG) logging.root.addHandler(filtered_handler) logging.root.setLevel(logging.DEBUG) task_thread = threading.Thread(target=call.run) task_thread.daemon = True task_thread.start() while True: try: # KeyboardInterrupts aren't seen until the .get() completes :S # So we set a timeout here to make sure we receive it next_event = call._output.get(block=True, timeout=1) except Queue.Empty: continue event_type = next_event['type'] if event_type == 'question': answer = cli.ask_question(next_event) call.input({ 'eventId': next_event['eventId'], 'data': answer, }) if event_type == 'progressStart': cli.start_progress(next_event) if event_type == 'progressEnd': cli.end_progress(next_event) if event_type == 'progress': cli.progress_bar(next_event) # TODO: handle situation of logging while progress bar is running # e.g. extra newline before using LOG.log if event_type == 'log': # all logging in our task thread comes out as events, which we then # plug back into the logging system, which then directs it to file/console output logging_level = getattr(logging, next_event.get('level', 'DEBUG')) LOG.log(logging_level, next_event.get('message', '')) elif event_type == 'success': return 0 elif event_type == 'error': # re-raise exception originally from other thread/process try: raise call.exception except RunningInForgeRoot: LOG.error( "You're trying to run commands in the build tools directory.\n" "You need to move to another directory outside of this one first.\n" ) except UpdateRequired: LOG.info("An update to these command line tools is required, downloading...") # TODO: refactor so that we don't need to instantiate Remote here config = build_config.load() remote = Remote(config) try: remote.update() LOG.info("Update complete, run your command again to continue") except Exception as e: LOG.error("Upgrade process failed: %s" % e) LOG.debug("%s" % traceback.format_exc(e)) LOG.error("You can get the tools from https://trigger.io/api/latest_tools and extract them yourself") LOG.error("Contact [email protected] if you have any further issues") except ForgeError as e: # thrown by us, expected LOG.error(next_event.get('message')) LOG.debug(str(next_event.get('traceback'))) except Exception: LOG.error("Something went wrong that we didn't expect:") LOG.error(next_event.get('message')) LOG.debug(str(next_event.get('traceback'))) LOG.error("See %s for more details" % ERROR_LOG_FILE) LOG.error("Please contact [email protected]") return 1 except KeyboardInterrupt: sys.stdout.write('\n') LOG.info('Exiting...') if call: call.interrupt() task_thread.join(timeout=5) return 1