Exemplo n.º 1
0
def error_handler(update: Update, context: CallbackContext):
    formatted_error = "HomeBot: Error encountered!\n"
    formatted_error += f"Command sent: {update.message.text}\n\n"
    formatted_error += format_exception(context.error)
    LOGE(formatted_error)
    update.message.reply_text(formatted_error)
    LOGE("End error handling")
Exemplo n.º 2
0
def error_handler(update: Update, context: CallbackContext):
    formatted_error = "HomeBot: Error encountered!\n"
    formatted_error += f"Command sent: {update.message.text}\n\n"
    formatted_error += ''.join(
        traceback.format_exception(type(context.error),
                                   context.error,
                                   context.error.__traceback__,
                                   limit=None,
                                   chain=True))
    LOGE(formatted_error)
    update.message.reply_text(formatted_error)
    LOGE("End error handling")
Exemplo n.º 3
0
	def ci(update: Update, context: CallbackContext):
		if not user_is_admin(update.message.from_user.id):
			update.message.reply_text("Error: You are not authorized to use CI function of this bot.\n"
									  "Ask to who host this bot to add you to the authorized people list")
			return

		if get_config("CI_CHANNEL_ID") == "":
			update.message.reply_text("Error: CI channel or user ID not defined")
			LOGE("CI channel or user ID not defined")
			return

		parser = CIParser(prog="/ci")
		parser.set_output(update.message.reply_text)
		parser.add_argument('project', help='CI project',
							nargs='?', default=None,)
		parser.add_argument('-s', '--status',
							action='store_true', help='show queue status')

		args, project_args = parser.parse_known_args(context.args)

		if args.status:
			update.message.reply_text(queue_manager.get_formatted_queue_list())
			return

		if args.project is None:
			parser.error("Please specify a project")

		try:
			project_class = import_module(f"homebot.modules.ci.projects.{args.project}", package="Project").Project
		except ModuleNotFoundError:
			update.message.reply_text(f"Error: Project script not found")
			return
		except Exception as e:
			text = "Error: Error while importing project:"
			text += format_exception(e)
			update.message.reply_text(text)
			LOGE(text)
			return

		try:
			project = project_class(update, context, project_args)
		except Exception as e:
			text = "Error: Project class initialization failed:\n"
			text += format_exception(e)
			update.message.reply_text(text)
			LOGE(text)
			return

		workflow = Workflow(project)
		queue_manager.put(workflow)
		update.message.reply_text("Workflow added to the queue")
		LOGI("Workflow added to the queue")
Exemplo n.º 4
0
	def __init__(self,
				 bot: 'Bot',
				 update_queue: Queue,
				 workers: int = 4,
				 exception_event: Event = None,
				 job_queue: 'JobQueue' = None):
		"""
		Initialize the dispatcher and its modules.
		"""
		super().__init__(bot, update_queue, workers=workers,
						 exception_event=exception_event, job_queue=job_queue)

		self.add_error_handler(error_handler, True)

		self.modules = []

		LOGI("Parsing modules")
		for module in modules:
			try:
				module_instance = module()
			except Exception as e:
				LOGE(f"Error initializing module {module.name}, will be skipped\n"
					 f"Error: {e}")
			else:
				self.modules.append(module_instance)
		LOGI("Modules parsed")

		LOGI("Loading modules")
		for module in self.modules:
			self.load_module(module)
		LOGI("Modules loaded")
Exemplo n.º 5
0
def disable_module(self: Dispatcher, module_name: str):
    """
	Unload a provided module and remove its command handler
	from the bot's dispatcher.
	"""
    LOGI(f"Loading module {module_name}")

    module = get_module(module_name)
    if module is None:
        raise ModuleNotFoundError(f"Module {module_name} not found")

    with self.modules_status_lock:
        if not module_name in self.modules_status:
            self.modules_status[module_name] = MODULE_STATUS_DISABLED

        if self.modules_status[module_name] == MODULE_STATUS_DISABLED:
            raise AttributeError("Module is already disabled")

        self.modules_status[module_name] = MODULE_STATUS_DISABLING

        try:
            for command in module.commands:
                self.add_handler(command.handler)
        except:
            LOGE(f"Failed to add handler for module {module_name}")
            self.modules_status[module_name] = MODULE_STATUS_ERROR

        self.modules_status[module_name] = MODULE_STATUS_DISABLED

    LOGI(f"Module {module_name} disabled")
Exemplo n.º 6
0
def register_modules(modules_path: Path):
    # Import all the modules and let them execute register_module()
    for module_name in [
            name for _, name, _ in iter_modules([str(modules_path)])
    ]:
        try:
            import_module(f'homebot.modules.{module_name}')
        except Exception as e:
            LOGE(f"Error importing module {module_name}:\n"
                 f"{format_exception(e)}")
Exemplo n.º 7
0
def get_bot_modules():
	modules = []
	for module_name in [name for _, name, _ in iter_modules([str(modules_path)])]:
		try:
			module_class = import_module(f'homebot.modules.{module_name}', package="Module").Module
		except Exception as e:
			LOGE(f"Error importing module {module_name}, will be skipped\n"
				 f"Error: {e}")
		else:
			modules.append(module_class)
	return modules
Exemplo n.º 8
0
 def run(self):
     while True:
         try:
             self.current_workflow = self.queue.get()
             workflow_name = self.current_workflow.project_name
             LOGI(f"CI workflow started, project: {workflow_name}")
             try:
                 self.current_workflow.run()
             except Exception as e:
                 message = "Unhandled exception from CI workflow:\n"
                 message += format_exception(e)
                 LOGE(message)
                 self.current_workflow.update.message.reply_text(
                     f"Error: {message}")
         except Exception as e:
             message = "Unhandled exception from QueueManager:\n"
             message += format_exception(e)
             LOGE(message)
         finally:
             LOGI(f"CI workflow finished, project: {workflow_name}")
             self.current_workflow = None
Exemplo n.º 9
0
 def run(self):
     while True:
         self.current_workflow = self.queue.get()
         self.running = True
         workflow_name = self.current_workflow.project_name
         LOGI(f"CI workflow started, project: {workflow_name}")
         try:
             self.current_workflow.run()
         except Exception as e:
             message = f"Unhandled exception from CI workflow: {type(e)}: {e}"
             LOGE(message)
             self.current_workflow.update.message.reply_text(
                 f"Error: {message}")
         self.running = False
         LOGI(f"CI workflow finished, project: {workflow_name}")
         self.current_workflow = None
Exemplo n.º 10
0
	def weather(update: Update, context: CallbackContext):
		try:
			city = update.message.text.split(' ', 1)[1]
		except IndexError:
			update.message.reply_text("City not provided")
			return
		if get_config("WEATHER_API_KEY", None) == None:
			update.message.reply_text("OpenWeatherMap API key not specified\n"
									  "Ask the bot hoster to configure it")
			LOGE("OpenWeatherMap API key not specified, get it at https://home.openweathermap.org/api_keys")
			return
		parameters = {
			"appid": get_config("WEATHER_API_KEY", None),
			"q": city,
			"units": get_config("WEATHER_TEMP_UNIT", "metric"),
		}
		temp_unit = TEMP_UNITS.get(get_config("WEATHER_TEMP_UNIT", None), "K")
		wind_unit = WIND_UNITS.get(get_config("WEATHER_TEMP_UNIT", None), "km/h")
		response = requests.get(url=URL, params=parameters).json()
		if response["cod"] != 200:
			update.message.reply_text(f"Error: {response['message']}")
			return
		city_name = response["name"]
		city_country = response["sys"]["country"]
		city_lat = response["coord"]["lat"]
		city_lon = response["coord"]["lon"]
		weather_type = response["weather"][0]["main"]
		weather_type_description = response["weather"][0]["description"]
		temp = response["main"]["temp"]
		temp_min = response["main"]["temp_min"]
		temp_max = response["main"]["temp_max"]
		humidity = response["main"]["humidity"]
		wind_speed = response["wind"]["speed"]
		update.message.reply_text(
			f"Current weather for {city_name}, {city_country} ({city_lat}, {city_lon}):\n"
			f"Weather: {weather_type} ({weather_type_description})\n"
			f"Temperature: {temp}{temp_unit} (Min: {temp_min}{temp_unit} Max: {temp_max}{temp_unit})\n"
			f"Humidity: {humidity}%\n"
			f"Wind: {wind_speed}{wind_unit}"
		)
Exemplo n.º 11
0
 def weather(update: Update, context: CallbackContext):
     try:
         city = update.message.text.split(' ', 1)[1]
     except IndexError:
         update.message.reply_text("City not provided")
         return
     try:
         weather = Weather()
     except AssertionError:
         update.message.reply_text("OpenWeatherMap API key not specified\n"
                                   "Ask the bot hoster to configure it")
         LOGE(
             "OpenWeatherMap API key not specified, get it at https://home.openweathermap.org/api_keys"
         )
         return
     try:
         response = weather.current_weather(city)
     except ConnectionError as err:
         update.message.reply_text(err.strerror)
         return
     city_name = response["name"]
     city_country = response["sys"]["country"]
     city_lat = response["coord"]["lat"]
     city_lon = response["coord"]["lon"]
     weather_type = response["weather"][0]["main"]
     weather_type_description = response["weather"][0]["description"]
     temp = response["main"]["temp"]
     temp_min = response["main"]["temp_min"]
     temp_max = response["main"]["temp_max"]
     humidity = response["main"]["humidity"]
     wind_speed = response["wind"]["speed"]
     update.message.reply_text(
         f"Current weather for {city_name}, {city_country} ({city_lat}, {city_lon}):\n"
         f"Weather: {weather_type} ({weather_type_description})\n"
         f"Temperature: {temp}{weather.temp_unit} (Min: {temp_min}{weather.temp_unit} Max: {temp_max}{weather.temp_unit})\n"
         f"Humidity: {humidity}%\n"
         f"Wind: {wind_speed}{weather.wind_unit}")
Exemplo n.º 12
0
    def build(self):
        project_dir = Path(
            f"{get_config('ci.main_dir', '')}/{self.name}-{self.version}")
        device_out_dir = project_dir / "out" / "target" / "product" / self.parsed_args.device

        artifacts = Artifacts(device_out_dir, self.artifacts)
        post_manager = PostManager(self, self.parsed_args.device, artifacts)

        if self.parsed_args.clean is True:
            clean_type = "clean"
        elif self.parsed_args.installclean is True:
            clean_type = "installclean"
        else:
            clean_type = "none"

        post_manager.update("Building")

        command = [
            bot_path / "modules" / "ci" / "projects" / "aosp" / "tools" /
            "building.sh", "--sources", project_dir, "--lunch_prefix",
            self.lunch_prefix, "--lunch_suffix", self.lunch_suffix,
            "--build_target", self.build_target, "--clean", clean_type,
            "--device", self.parsed_args.device
        ]

        last_edit = datetime.now()
        process = subprocess.Popen(command,
                                   encoding="UTF-8",
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.STDOUT)
        while True:
            output = process.stdout.readline()
            if output == '' and process.poll() is not None:
                break
            if not output:
                continue

            now = datetime.now()
            if (now - last_edit).seconds < 150:
                continue

            result = re.search(r"\[ +([0-9]+% [0-9]+/[0-9]+)\]",
                               output.strip())
            if result is None:
                continue
            result_split = str(result.group(1)).split()
            if len(result_split) != 2:
                continue

            percentage, targets = re.split(" +", result.group(1))
            post_manager.update(f"Building: {percentage} ({targets})")

            last_edit = now

        returncode = process.poll()

        # Process return code
        build_result = ERROR_CODES.get(returncode,
                                       "Build failed: Unknown error")

        post_manager.update(build_result)

        needs_logs_upload = NEEDS_LOGS_UPLOAD.get(returncode, False)
        if needs_logs_upload != False:
            log_file = open(project_dir / needs_logs_upload, "rb")
            self.context.bot.send_document(get_config("ci.channel_id"),
                                           log_file)
            log_file.close()

        if returncode != SUCCESS or get_config("ci.upload_artifacts",
                                               False) is not True:
            return

        # Upload artifacts
        try:
            uploader = Uploader()
        except Exception as e:
            post_manager.update(f"{build_result}\n"
                                f"Upload failed: {type(e)}: {e}")
            return

        artifacts.update()

        post_manager.update(build_result)

        for artifact in artifacts.artifacts:
            artifact.status = STATUS_UPLOADING
            post_manager.update(build_result)

            try:
                uploader.upload(
                    artifact.path,
                    Path(self.category) / self.parsed_args.device / self.name /
                    self.android_version)
            except Exception as e:
                artifact.status = f"{STATUS_NOT_UPLOADED}: {type(e)}: {e}"
                LOGE(f"Error while uploading artifact {artifact.name}:\n"
                     f"{format_exception(e)}")
            else:
                artifact.status = STATUS_UPLOADED

            post_manager.update(build_result)