def search(word: str, exact_name: bool = False) -> List[dict]: apps = [] res = run_cmd('{} find "{}"'.format(BASE_CMD, word), print_error=False) if res: res = res.split('\n') if not res[0].startswith('No matching'): for idx, app_str in enumerate(res): if idx > 0 and app_str: app_data = [word for word in app_str.split(' ') if word] if exact_name and app_data[0] != word: continue apps.append({ 'name': app_data[0], 'version': app_data[1], 'publisher': app_data[2], 'notes': app_data[3] if app_data[3] != '-' else None, 'summary': app_data[4] if len(app_data) == 5 else '', 'rev': None, 'tracking': None, 'type': None }) if exact_name and len(apps) > 0: break return apps
def map_required_by(names: Iterable[str]) -> Dict[str, Set[str]]: output = run_cmd('pacman -Qi {}'.format(' '.join(names))) if output: res = {} latest_name, required = None, None for l in output.split('\n'): if l: if l[0] != ' ': line = l.strip() field_sep_idx = line.index(':') field = line[0:field_sep_idx].strip() if field == 'Name': val = line[field_sep_idx + 1:].strip() latest_name = val elif field == 'Required By': val = line[field_sep_idx + 1:].strip() required = set() if val != 'None': required.update((d for d in val.split(' ') if d)) elif latest_name and required is not None: res[latest_name] = required latest_name, required = None, None elif latest_name and required is not None: required.update( required.update( (d for d in l.strip().split(' ') if d))) return res
def get_commit(app_id: str, branch: str, installation: str) -> Optional[str]: info = run_cmd('flatpak info {} {} --{}'.format(app_id, branch, installation)) if info: commits = RE_COMMIT.findall(info) if commits: return commits[0][1].strip()
def map_available_packages() -> Optional[Dict[str, Any]]: output = run_cmd('pacman -Sl') if output: res = dict() for line in output.split('\n'): line_strip = line.strip() if line_strip: package_data = line.split(' ') if len(package_data) >= 3: pkgname = package_data[1].strip() if pkgname: res[pkgname] = { 'v': package_data[2].strip(), 'r': package_data[0].strip(), 'i': len(package_data) == 4 and 'installed' in package_data[3] } return res
def map_required_dependencies(*names: str) -> Dict[str, Set[str]]: output = run_cmd('pacman -Qi {}'.format(' '.join(names) if names else '')) if output: res = {} latest_name, deps, latest_field = None, None, None for l in output.split('\n'): if l: if l[0] != ' ': line = l.strip() field_sep_idx = line.index(':') field = line[0:field_sep_idx].strip() if field == 'Name': val = line[field_sep_idx + 1:].strip() latest_name = val deps = None elif field == 'Depends On': val = line[field_sep_idx + 1:].strip() if deps is None: deps = set() if val != 'None': deps.update((dep for dep in val.split(' ') if dep)) elif latest_name and deps is not None: res[latest_name] = deps latest_name, deps, latest_field = None, None, None elif latest_name and deps is not None: deps.update((dep for dep in l.split(' ') if dep)) return res
def update_node(self, version: str, version_url: str, watcher: ProcessWatcher = None) -> bool: Path(ENV_PATH).mkdir(parents=True, exist_ok=True) if not os.path.exists(NODE_DIR_PATH): return self._download_and_install(version=version, version_url=version_url, watcher=watcher) else: installed_version = system.run_cmd('{} --version'.format(NODE_BIN_PATH), print_error=False) if installed_version: installed_version = installed_version.strip() if installed_version.startswith('v'): installed_version = installed_version[1:] self.logger.info('Node versions: installed ({}), cloud ({})'.format(installed_version, version)) if version != installed_version: self.logger.info("The NodeJs installed version is different from the Cloud.") return self._download_and_install(version=version, version_url=version_url, watcher=watcher) else: self.logger.info("Node is already up to date") return True else: self.logger.warning("Could not determine the current NodeJS installed version") self.logger.info("Removing {}".format(NODE_DIR_PATH)) try: shutil.rmtree(NODE_DIR_PATH) return self._download_and_install(version=version, version_url=version_url, watcher=watcher) except: self.logger.error('Could not delete the dir {}'.format(NODE_DIR_PATH)) return False
def update_srcinfo(project_dir: str, custom_user: Optional[str] = None) -> bool: updated_src = system.run_cmd('makepkg --printsrcinfo', cwd=project_dir, custom_user=custom_user) if updated_src: return write_as_user(content=updated_src, file_path=f"{project_dir}/.SRCINFO", user=custom_user) return False
def read_installed(info_path: str) -> List[dict]: res = run_cmd('{} list'.format(BASE_CMD), print_error=False) apps = [] if res and len(res) > 0: lines = res.split('\n') if not lines[0].startswith('error'): for idx, app_str in enumerate(lines): if idx > 0 and app_str: apps.append(app_str_to_json(app_str)) info_out = new_subprocess( ['cat', *[info_path.format(a['name']) for a in apps]]).stdout idx = -1 for o in new_subprocess( ['grep', '-E', '(summary|apps)', '--colour=never'], stdin=info_out).stdout: if o: line = o.decode() if line.startswith('summary:'): idx += 1 apps[idx]['summary'] = line.split(':')[1].strip() else: apps[idx]['apps_field'] = True return apps
def get_app_commits_data(app_ref: str, origin: str, installation: str, full_str: bool = True) -> List[dict]: log = run_cmd('{} remote-info --log {} {} --{}'.format( 'flatpak', origin, app_ref, installation)) if not log: raise NoInternetException() res = re.findall(r'(Commit|Subject|Date):\s(.+)', log) commits = [] commit = {} for idx, data in enumerate(res): attr = data[0].strip().lower() commit[attr] = data[1].strip() if attr == 'commit': commit[attr] = commit[attr] if full_str else commit[attr][0:8] if attr == 'date': commit[attr] = datetime.strptime(commit[attr], '%Y-%m-%d %H:%M:%S +0000') if (idx + 1) % 3 == 0: commits.append(commit) commit = {} return commits
def get_app_info(app_id: str, branch: str, installation: str): try: return run_cmd('{} info {} {}'.format('flatpak', app_id, branch, '--{}'.format(installation))) except: traceback.print_exc() return ''
def get_info(app_name: str, attrs: tuple = None): full_info_lines = run_cmd('{} info {}'.format(BASE_CMD, app_name)) data = {} if full_info_lines: re_attrs = r'\w+' if not attrs else '|'.join(attrs) info_map = re.findall(r'({}):\s+(.+)'.format(re_attrs), full_info_lines) for info in info_map: val = info[1].strip() if info[0] == 'installed': val_split = [s for s in val.split(' ') if s] data['version'] = val_split[0] if len(val_split) > 2: data['size'] = val_split[2] else: data[info[0]] = val if not attrs or 'description' in attrs: desc = re.findall(r'\|\n+((\s+.+\n+)+)', full_info_lines) data['description'] = ''.join([ w.strip() for w in desc[0][0].strip().split('\n') ]).replace('.', '.\n') if desc else None if not attrs or 'commands' in attrs: commands = re.findall(r'commands:\s*\n*((\s+-\s.+\s*\n)+)', full_info_lines) data['commands'] = commands[0][0].strip().replace( '- ', '').split('\n') if commands else None return data
def get_commit(app_id: str, branch: str, installation: str) -> Optional[str]: info = run_cmd(f'flatpak info {app_id} {branch} --{installation}') if info: commits = RE_COMMIT.findall(info) if commits: return commits[0][1].strip()
def guess_repository(name: str) -> Tuple[str, str]: if not name: raise Exception("'name' cannot be None or blank") only_name = RE_DEP_OPERATORS.split(name)[0] res = run_cmd('pacman -Ss {}'.format(only_name)) if res: lines = res.split('\n') if lines: for line in lines: if line and not line.startswith(' '): data = line.split('/') line_name, line_repo = data[1].split(' ')[0], data[0] provided = read_provides(line_name) if provided: found = { p for p in provided if only_name == RE_DEP_OPERATORS.split(p)[0] } if found: return line_name, line_repo
def search(words: str) -> Dict[str, dict]: output = run_cmd('pacman -Ss ' + words) if output: found, current = {}, {} for l in output.split('\n'): if l: if l.startswith(' '): current['description'] = l.strip() found[current['name']] = current del current['name'] current = None else: if current is None: current = {} repo_split = l.split('/') current['repository'] = repo_split[0] data_split = repo_split[1].split(' ') current['name'] = data_split[0] version = data_split[1].split(':') current['version'] = version[0] if len( version) == 1 else version[1] return found
def get_app_commits_data(app_ref: str, origin: str) -> List[dict]: log = run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref)) if not log: raise NoInternetException() res = re.findall(r'(Commit|Subject|Date):\s(.+)', log) commits = [] commit = {} for idx, data in enumerate(res): attr = data[0].strip().lower() commit[attr] = data[1].strip() if attr == 'date': commit[attr] = datetime.strptime(commit[attr], '%Y-%m-%d %H:%M:%S +0000') if (idx + 1) % 3 == 0: commits.append(commit) commit = {} return commits
def map_conflicts_with(names: Iterable[str], remote: bool) -> Dict[str, Set[str]]: output = run_cmd('pacman -{}i {}'.format('S' if remote else 'Q', ' '.join(names))) if output: res = {} latest_name, conflicts = None, None for l in output.split('\n'): if l: if l[0] != ' ': line = l.strip() field_sep_idx = line.index(':') field = line[0:field_sep_idx].strip() if field == 'Name': val = line[field_sep_idx + 1:].strip() latest_name = val elif field == 'Conflicts With': val = line[field_sep_idx + 1:].strip() conflicts = set() if val != 'None': conflicts.update((d for d in val.split(' ') if d)) elif latest_name and conflicts is not None: res[latest_name] = conflicts latest_name, conflicts = None, None elif latest_name and conflicts is not None: conflicts.update( conflicts.update( (d for d in l.strip().split(' ') if d))) return res
def check_node_installed(self, version: str) -> bool: if not os.path.exists(NODE_DIR_PATH): return False else: installed_version = system.run_cmd( '{} --version'.format(NODE_BIN_PATH), print_error=False) if installed_version: installed_version = installed_version.strip() if installed_version.startswith('v'): installed_version = installed_version[1:] self.logger.info( 'Node versions: installed ({}), cloud ({})'.format( installed_version, version)) if version != installed_version: self.logger.info( "The NodeJs installed version is different from the Cloud." ) return False else: self.logger.info("Node is already up to date") return True else: self.logger.warning( "Could not determine the current NodeJS installed version") return False
def search(words: str) -> Dict[str, dict]: output = run_cmd('pacman -Ss ' + words, print_error=False) found = {} if output: current = {} for l in output.split('\n'): if l: if l.startswith(' '): current['description'] = l.strip() found[current['name']] = current del current['name'] current = None else: if current is None: current = {} repo_split = l.split('/') current['repository'] = repo_split[0] data_split = repo_split[1].split(' ') current['name'] = data_split[0] current['version'] = data_split[1] return found
def get_app_commits(app_ref: str, origin: str) -> List[str]: log = run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref)) if log: return re.findall(r'Commit+:\s(.+)', log) else: raise NoInternetException()
def find_one_match(name: str) -> Optional[str]: output = run_cmd('pacman -Ssq {}'.format(name), print_error=False) if output: matches = [l.strip() for l in output.split('\n') if l.strip()] if matches and len(matches) == 1: return matches[0]
def list_installed_names() -> Set[str]: res = run_cmd('{} list'.format(BASE_CMD), print_error=False) if res: lines = res.split('\n') if not lines[0].startswith('error'): return {l.split(' ')[0].strip() for l in lines[1:] if l}
def read_installed(self, disk_loader: DiskCacheLoader, limit: int = -1, only_apps: bool = False, pkg_types: Set[Type[SoftwarePackage]] = None, internet_available: bool = None, connection: sqlite3.Connection = None) -> SearchResult: res = SearchResult([], [], 0) if os.path.exists(INSTALLATION_PATH): installed = run_cmd('ls {}*/data.json'.format(INSTALLATION_PATH), print_error=False) if installed: names = set() for path in installed.split('\n'): if path: with open(path) as f: app = AppImage(installed=True, **json.loads(f.read())) app.icon_url = app.icon_path res.installed.append(app) names.add("'{}'".format(app.name.lower())) if res.installed: con = self._get_db_connection( DB_APPS_PATH) if not connection else connection if con: try: cursor = con.cursor() cursor.execute( query.FIND_APPS_BY_NAME.format( ','.join(names))) for tup in cursor.fetchall(): for app in res.installed: if app.name.lower() == tup[0].lower() and ( not app.github or app.github.lower() == tup[1].lower()): app.update = tup[2] > app.version if app.update: app.latest_version = tup[2] app.url_download_latest_version = tup[ 3] break except: traceback.print_exc() finally: if not connection: self._close_connection(DB_APPS_PATH, con) res.total = len(res.installed) return res
def list_output_files(project_dir: str, custom_pkgbuild_path: Optional[str] = None, custom_user: Optional[str] = None) -> Set[str]: cmd = f"makepkg --packagelist{' -p {}'.format(custom_pkgbuild_path) if custom_pkgbuild_path else ''}" output = system.run_cmd(cmd=cmd, print_error=False, cwd=project_dir, custom_user=custom_user) if output: return {p.strip() for p in output.split('\n') if p} return set()
def list_repository_updates() -> Dict[str, str]: output = run_cmd('pacman -Qu') res = {} if output: for line in output.split('\n'): if line: line_split = line.split(' ') res[line_split[0]] = line_split[-1] return res
def update_srcinfo(project_dir: str) -> bool: updated_src = run_cmd('makepkg --printsrcinfo', cwd=project_dir) if updated_src: with open('{}/.SRCINFO'.format(project_dir), 'w+') as f: f.write(updated_src) return True return False
def get_distro(): if os.path.exists('/etc/arch-release'): return 'arch' if os.path.exists('/proc/version'): if 'ubuntu' in run_cmd('cat /proc/version').lower(): return 'ubuntu' return 'unknown'
def get_history(self, pkg: ArchPackage) -> PackageHistory: temp_dir = '{}/build_{}'.format(BUILD_DIR, int(time.time())) try: Path(temp_dir).mkdir(parents=True) run_cmd('git clone ' + URL_GIT.format(pkg.name), print_error=False, cwd=temp_dir) clone_path = '{}/{}'.format(temp_dir, pkg.name) pkgbuild_path = '{}/PKGBUILD'.format(clone_path) commits = git.list_commits(clone_path) if commits: history, status_idx = [], -1 for idx, commit in enumerate(commits): with open(pkgbuild_path) as f: pkgdict = aur.map_pkgbuild(f.read()) if status_idx < 0 and '{}-{}'.format( pkgdict.get('pkgver'), pkgdict.get('pkgrel')) == pkg.version: status_idx = idx history.append({ '1_version': pkgdict['pkgver'], '2_release': pkgdict['pkgrel'], '3_date': commit['date'] }) # the number prefix is to ensure the rendering order if idx + 1 < len(commits): if not run_cmd('git reset --hard ' + commits[idx + 1]['commit'], cwd=clone_path): break return PackageHistory(pkg=pkg, history=history, pkg_status_idx=status_idx) finally: if os.path.exists(temp_dir): shutil.rmtree(temp_dir)
def map_download_sizes(pkgs: List[str]) -> Dict[str, int]: # bytes: output = run_cmd('pacman -Si {}'.format(' '.join(pkgs))) if output: return { pkgs[idx]: size_to_byte(float(size[0]), size[1]) for idx, size in enumerate(RE_DOWNLOAD_SIZE.findall(output)) } return {}
def get_installed_size(pkgs: List[str]) -> Dict[str, int]: # bytes output = run_cmd('pacman -Qi {}'.format(' '.join(pkgs))) if output: return { pkgs[idx]: size_to_byte(float(size[0]), size[1]) for idx, size in enumerate(RE_INSTALLED_SIZE.findall(output)) } return {}
def get_build_date(pkgname: str) -> str: output = run_cmd('pacman -Qi {}'.format(pkgname)) if output: bdate_line = [ l for l in output.split('\n') if l.startswith('Build Date') ] if bdate_line: return ':'.join(bdate_line[0].split(':')[1:]).strip()