def _proc_check(): argv = [path, '-m', 'pip', 'check'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') _deps_pkgs = list() try: # pip check exits with a non-zero status if any packages are missing dependencies proc = subprocess.run(argv, stdout=subprocess.PIPE, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.stdout.decode() print_text(context, self._file, redirect=self._vflag) for line in filter(None, context.strip().splitlines()): if line == 'No broken requirements found.': return set() if 'which is not installed' in line: _deps_pkgs.append(line.split()[3][:-1]) else: _deps_pkgs.append(line.split()[4][:-1]) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') return set(_deps_pkgs)
def _proc_logging(self, path): text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._qflag) suffix = path.replace('/', ':') logfile = os.path.join(self._logroot, f'{self.log}-{suffix}{self.ext}') argv = [path, 'list', '--global', '--json'] if self._long: argv.append('--long') args = ' '.join(argv) print_scpt(args, self._file, redirect=self._qflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) _real_pkgs = dict() else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) content = json.loads(context.strip()) with open(logfile, 'w') as file: json.dump(content, file, indent=2) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _proc_logging(self, path): text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._qflag) suffix = path.replace('/', ':') with tempfile.NamedTemporaryFile() as _temp_file: logfile = os.path.join(self._logroot, f'{self.log}-{suffix}{self.ext}') argv = [ path, 'bundle', 'dump', '--force', f'--file={_temp_file.name}' ] print_scpt(argv, self._file, redirect=self._qflag) script(argv, self._file, shell=True, timeout=self._timeout, redirect=self._vflag) with open(_temp_file.name, 'r') as file: context = file.read() print_text(context, get_logfile(), redirect=self._vflag) with open(logfile, 'w') as file: file.writelines( filter(lambda s: s.startswith('brew'), context.strip().splitlines(True))) # pylint: disable=filter-builtin-not-iterating
def _proc_check(): argv = [path, 'missing', f'--hide={",".join(self._ignore)!r}'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') _deps_pkgs = list() try: # brew missing exits with a non-zero status if any formulae are missing dependencies proc = subprocess.run(argv, stdout=subprocess.PIPE, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.stdout.decode() print_text(context, self._file, redirect=self._vflag) for line in filter(None, context.strip().splitlines()): _deps_pkgs.extend(line.split()[1:]) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') return set(_deps_pkgs)
def _check_list(self, path): text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'upgrade'] argv.extend(self._logging_opts) argv.append('--no-color') argv.append('--no-json') argv.append('--list') args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = list() for line in filter(lambda s: '->' in s, context.strip().splitlines()): _temp_pkgs.append(re.sub(r'.* (.*) .* -> .*', r'\1', line)) self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _check_list(self, path): text = f'Checking installed {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'cask', 'list'] argv.extend(self._logging_opts) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() self._var__temp_pkgs = set(context.strip().split()) # pylint: disable=attribute-defined-outside-init print_text(context, self._file, redirect=self._vflag) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _check_list(self, path): argv = [path, '-m', 'pip', 'freeze'] argv.extend(self._logging_opts) text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._qflag) _temp_pkgs = list() for line in filter(None, context.strip().splitlines()): _temp_pkgs.append(line.split('==')[0]) self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _proc_logging(self, path): text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._qflag) suffix = path.replace('/', ':') logfile = os.path.join(self._logroot, f'{self.log}-{suffix}{self.ext}') argv = [path, '-m', 'pip', 'freeze'] if self._exclude_editable: argv.append('--exclude-editable') args = ' '.join(argv) print_scpt(args, self._file, redirect=self._qflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) _real_pkgs = dict() else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) with open(logfile, 'w') as file: file.writelines(filter(None, context.strip().splitlines(True))) # pylint: disable=filter-builtin-not-iterating finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _print_dependency_tree(package, dependencies): with tempfile.NamedTemporaryFile() as dumpfile: dumper = dictdumper.Tree(dumpfile.name, quiet=True) dumper(dependencies, name=package) with open(dumpfile.name) as file: for line in filter(None, file): print_text(line.strip(), self._file)
def make_storage(config, today, quiet=False, verbose=False, logfile=os.devnull): arclist = list() logdate = datetime.date.strftime(today, r'%y%m%d') dskpath = config['Path']['dskdir'] tarpath = os.path.join(config['Path']['logdir'], 'tarfile') if not os.path.isdir(dskpath): return arclist if not os.path.isdir(tarpath): return arclist text = f'Storing ancient archives at external hard disk {under}{dskpath}{reset}' print_info(text, logfile, redirect=quiet) days = calendar.monthrange(year=today.year, month=today.month)[1] ctime = datetime.datetime.fromtimestamp(os.stat(tarpath).st_birthtime) if (today - ctime) > datetime.timedelta(days=days): glob_list = glob.glob(os.path.join(tarpath, '*/*.tar.xz')) if glob_list: with tempfile.TemporaryDirectory() as tmppath: arcdate = datetime.date.strftime(ctime, r'%y%m%d') tarname = os.path.join(tmppath, f'{arcdate}-{logdate}.tar.bz') if verbose: print_scpt(f'tar -cjf {tarname} {tarpath}', logfile, redirect=quiet) else: print_scpt(f'tar -cjvf {tarname} {tarpath}', logfile, redirect=verbose) with tarfile.open(tarname, 'w:bz2') as bz: for absname in glob_list: arcname = pathlib.Path(absname).relative_to(tarpath) bz.add(absname, arcname) arclist.append(absname) print_text(absname, logfile, redirect=verbose) arcfile = os.path.join(config['Path']['arcdir'], 'archive.zip') if verbose: print_scpt(f'tar -cZf {arcfile} {tarname}', logfile, redirect=quiet) else: print_scpt(f'tar -cZvf {arcfile} {tarname}', logfile, redirect=verbose) with zipfile.ZipFile(arcfile, 'a', zipfile.ZIP_DEFLATED) as zf: arcname = os.path.split(tarname)[1] zf.write(tarname, arcname) print_text(tarname, logfile, redirect=verbose) shutil.rmtree(tarpath) return arclist
def _fetch_dependency(package, depth): if depth == 0: return dict() depth -= 1 dependencies = _data_pkgs.get(package) if dependencies is not None: return dependencies text = f'Searching dependencies of {self.desc[0]} {under}{package}{reset}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'deps', '--installed', '-1'] if self._include_build: argv.append('--include-build') if self._include_optional: argv.append('--include-optional') if self._include_test: argv.append('--include-test') if self._skip_recommended: argv.append('--skip-recommended') if self._include_requirements: argv.append('--include-requirements') argv.append(package) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') _deps_pkgs = dict() try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: self._fail.append(package) with contextlib.suppress(KeyError): self._var__temp_pkgs.remove(package) print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _list_pkgs.append(package) for item in filter(None, context.strip().splitlines()): if item in self._var__temp_pkgs: self._var__temp_pkgs.remove(item) _deps_pkgs[item] = _fetch_dependency(item, depth) _data_pkgs.update(_deps_pkgs) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') return _deps_pkgs
def _check_list(self, path): argv = [path, '-m', 'pip', 'list', '--outdated'] if self._pre: argv.append('--pre') argv.extend(self._logging_opts) text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) temp = copy.copy(argv) temp.append('--format=columns') args = ' '.join(temp) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') argv.append('--format=json') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: # self._var__temp_pkgs = set(map(lambda pkg: pkg.split('==')[0], proc.decode().split())) text = proc.decode() start = text.rfind('[') stop = text.rfind(']') + 1 context = json.loads(text[start:stop]) self._var__temp_pkgs = set(map(lambda item: item['name'], context)) # pylint: disable=attribute-defined-outside-init prefix = text[:start] if prefix: print_text(prefix, self._file, redirect=self._vflag) if context: name_len = max(7, max(map(lambda item: len(item['name']), context), default=7)) version_len = max(7, max(map(lambda item: len(item['version']), context), default=7)) latest_version_len = max(6, max(map(lambda item: len(item['latest_version']), context), default=6)) latest_filetype_len = max(4, max(map(lambda item: len(item['latest_filetype']), context), default=4)) def _pprint(package, version, latest, filetype): text = [package.ljust(name_len), version.ljust(version_len), latest.ljust(latest_version_len), filetype.ljust(latest_filetype_len)] return ' '.join(text) print_text(_pprint('Package', 'Version', 'Latest', 'Type'), self._file, redirect=self._vflag) print_text(' '.join(map(lambda length: '-' * length, [name_len, version_len, latest_version_len, latest_filetype_len])), self._file, redirect=self._vflag) for item in context: print_text(_pprint(item['name'], item['version'], item['latest_version'], item['latest_filetype']), self._file, redirect=self._vflag) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _check_list(self, path): text = 'Updating RubyGems database' print_info(text, self._file, redirect=self._qflag) argv = [path, 'update', '--system'] if self._quiet: argv.append('--quiet') if self._verbose: argv.append('--verbose') args = ' '.join(argv) print_scpt(args, self._file, redirect=self._qflag) sudo(argv, self._file, self._password, redirect=self._qflag, verbose=self._vflag) text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'outdated'] if self._quiet: argv.append('--quiet') if self._verbose: argv.append('--verbose') argv.extend(self._logging_opts) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = list() for item in filter(lambda s: re.match(r'\w* \(.*\)', s), context.strip().splitlines()): _temp_pkgs.append(item.split()[0]) self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init # self._var__temp_pkgs = set(map(lambda s: s.split()[0], filter(None, context.strip().splitlines()))) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _check_pkgs(self, path): text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'list'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) _real_pkgs = set() else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _list_pkgs = dict() for line in context.strip().splitlines(): match = re.match(r'(?P<code>\d{9}) (?P<name>.*?) \(.+?\)', line) if match is None: continue _list_pkgs[match.group('name')] = match.group('code') _real_pkgs = set(_list_pkgs.keys()) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') text = 'Checking existence of specified packages' print_info(text, self._file, redirect=self._vflag) _temp_pkgs = list() _lost_pkgs = list() for package in self._packages: if package in _real_pkgs: _temp_pkgs.append(package) else: _lost_pkgs.append(package) self._lost.extend(_lost_pkgs) self._var__dict_pkgs = _list_pkgs # pylint: disable=attribute-defined-outside-init self._var__real_pkgs = set(_real_pkgs) # pylint: disable=attribute-defined-outside-init self._var__lost_pkgs = set(_lost_pkgs) # pylint: disable=attribute-defined-outside-init self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init
def _fetch_dependency(package, depth): if depth == 0: return dict() depth -= 1 dependencies = _data_pkgs.get(package) if dependencies is not None: return dependencies text = f'Searching dependencies of {self.desc[0]} {under}{package}{reset}' print_info(text, self._file, redirect=self._vflag) argv = [path, '-m', 'pip', 'show', package] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') _deps_pkgs = dict() try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: self._fail.append(package) with contextlib.suppress(KeyError): self._var__temp_pkgs.remove(package) print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) requirements = set() for line in context.strip().splitlines(): match = re.match(r'Requires: (.*)', line) if match is not None: requirements = set(match.groups()[0].split(', ')) break _list_pkgs.append(package) for item in filter(None, requirements): if item in self._var__temp_pkgs: self._var__temp_pkgs.remove(item) _deps_pkgs[item] = _fetch_dependency(item, depth) _data_pkgs.update(_deps_pkgs) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') return _deps_pkgs
def _check_exec(self): try: subprocess.check_call(['brew', 'command', 'bundle'], stdout=subprocess.DEVNULL, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) print(f'macdaily-{self.cmd}: {red_bg}{flash}mas{reset}: command not found', file=sys.stderr) text = (f'macdaily-{self.cmd}: {red}mas{reset}: you may find Bundler on ' f'{purple_bg}{under}https://github.com/Homebrew/homebrew-bundle{reset}, ' f'or install Bundler through following command -- ' f"`{bold}brew tap homebrew/bundle{reset}'") print_term(text, self._file, redirect=self._qflag) return False self._var__exec_path = shutil.which('brew') return True
def run_script( argv, quiet=False, verbose=False, sudo=False, # pylint: disable=dangerous-default-value password=None, logfile=os.devnull, env=os.environ): args = ' '.join(argv) print_scpt(args, logfile, verbose) with open(logfile, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: if sudo: if password is not None: sudo_argv = ['sudo', '--stdin', '--prompt=Password:\n'] sudo_argv.extend(argv) with make_pipe(password, verbose) as pipe: proc = subprocess.check_output(sudo_argv, stdin=pipe.stdout, stderr=make_stderr(verbose), env=env) else: sudo_argv = ['sudo'] sudo_argv.extend(argv) proc = subprocess.check_output(sudo_argv, stderr=make_stderr(verbose), env=env) else: proc = subprocess.check_output(argv, stderr=make_stderr(verbose), env=env) except subprocess.CalledProcessError as error: print_text(traceback.format_exc(), logfile, redirect=verbose) print_term( f"macdaily: {red}error{reset}: " f"command `{bold}{' '.join(error.cmd)!r}{reset}' failed", logfile, redirect=quiet) raise else: context = proc.decode() print_text(context, logfile, redirect=verbose) finally: with open(logfile, 'a') as file: file.write(f'Script done on {date()}\n')
def _check_pkgs(self, path): text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'list', '--no-versions'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) _real_pkgs = set() else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = list() for package in filter(None, context.strip().splitlines()): if package.startswith('***'): continue _temp_pkgs.append(package) _real_pkgs = set(_temp_pkgs) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') text = 'Checking existence of specified packages' print_info(text, self._file, redirect=self._vflag) _temp_pkgs = list() _lost_pkgs = list() for package in self._packages: if package in _real_pkgs: _temp_pkgs.append(package) else: _lost_pkgs.append(package) self._lost.extend(_lost_pkgs) self._var__real_pkgs = set(_real_pkgs) # pylint: disable=attribute-defined-outside-init self._var__lost_pkgs = set(_lost_pkgs) # pylint: disable=attribute-defined-outside-init self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init
def _check_list(self, path): if (self._brew_renew is None or time.time() - self._brew_renew >= 300): self._proc_renew(path) self._brew_renew = time.time() if self._exhaust: self._exhaust_check(path) return text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'cask', 'outdated'] if self._quiet: argv.append('--quiet') if self._verbose: argv.append('--verbose') if self._greedy: argv.append('--greedy') argv.extend(self._logging_opts) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = list() for line in filter(None, context.strip().splitlines()): _temp_pkgs.append(line.split(maxsplit=1)[0]) self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _loc_exec(self): if not (self._brew and self._system): self._exec = {self._var__exec_path} else: _exec_path = list() if self._brew: text = 'Looking for brewed Ruby' print_info(text, self._file, redirect=self._vflag) argv = ['brew', '--prefix'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr( self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _glob_path = glob.glob( os.path.join(context.strip(), 'Cellar/ruby/*/bin/gem')) _glob_path.sort(reverse=True) _exec_path.append(_glob_path[0]) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') if self._system: text = 'Looking for macOS-provided Ruby' print_info(text, self._file, redirect=self._vflag) if os.path.exists('/usr/bin/gem'): _exec_path.append('/usr/bin/gem') else: _exec_path.extend(glob.glob('/System/Library/Frameworks/Ruby.framework/Versions/Current/usr/bin/gem')) # pylint: disable=line-too-long self._exec = set(_exec_path) del self._var__exec_path
def _script(argv=SHELL, file='typescript', password=None, yes=None, redirect=False, executable=SHELL, prefix=None, suffix=None, timeout=None): if suffix is not None: argv = f'{_merge(argv)} {suffix}' argc = f'script -q /dev/null {executable} -c "' if yes is not None: argc = f'{argc} yes {yes} |' argv = f'{argc} {_merge(argv)}" | tee -a >({_ansi2text(password)} | col -b >> {file}) | {_text2dim(password)}' if prefix is not None: argv = f'{prefix} {argv}' # argv = f'set -x; {argv}' mode = None with contextlib.suppress(tty.error): mode = tty.tcgetattr(0) try: returncode = subprocess.check_call(argv, shell=True, executable=executable, timeout=timeout, stderr=make_stderr(redirect)) except subprocess.SubprocessError as error: if mode is not None: with contextlib.suppress(tty.error): if tty.tcgetattr(0) != mode: tty.tcsetattr(0, tty.TCSAFLUSH, mode) text = traceback.format_exc().replace('\n', '\\n') if password is not None: text = text.replace(password, PWD.pw_passwd) print_text(text, file, redirect=redirect) returncode = getattr(error, 'returncode', 1) # if password is not None: # with contextlib.suppress(subprocess.SubprocessError): # subprocess.run(['chown', getpass.getuser(), file], stdout=subprocess.DEVNULL) return returncode
def _proc_dependency(package, _know_pkgs): _deps_pkgs = {package} if self._ignore_deps: return _deps_pkgs text = f'Searching dependencies of {self.desc[0]} {under}{package}{reset}' print_info(text, self._file, redirect=self._vflag) argv = [path, '-m', 'pip', 'show', package] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') _temp_pkgs = set() try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) for line in filter(lambda s: s.startswith('Requires: '), context.strip().splitlines()): _temp_pkgs = set( map(lambda s: s.rstrip(','), line.split()[1:])) - _know_pkgs _deps_pkgs |= _temp_pkgs break finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') for pkg in _temp_pkgs: _temp_pkgs = _proc_dependency(pkg, _know_pkgs) _deps_pkgs |= _temp_pkgs _know_pkgs |= _temp_pkgs return _deps_pkgs
def _check_list(self, path): text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, '--list'] argv.extend(self._logging_opts) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__rcmd_pkgs = set() # pylint: disable=attribute-defined-outside-init self._var__norm_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _rcmd_pkgs = list() _norm_pkgs = list() for package in filter(lambda s: re.match(r'^\W*[-*]', s), context.strip().splitlines()): flag, name = package.strip().split(maxsplit=1) if flag == '*': _rcmd_pkgs.append(name) if flag == '-': _norm_pkgs.append(name) self._var__rcmd_pkgs = set(_rcmd_pkgs) # pylint: disable=attribute-defined-outside-init self._var__norm_pkgs = set(_norm_pkgs) # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') self._var__temp_pkgs = self._var__rcmd_pkgs | self._var__norm_pkgs # pylint: disable=attribute-defined-outside-init
def _proc_dependency(package): _deps_pkgs = [package] if self._ignore_deps: return _deps_pkgs text = f'Searching dependencies of {self.desc[0]} {under}{package}{reset}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'deps', '--installed', '-n'] if self._include_build: argv.append('--include-build') if self._include_optional: argv.append('--include-optional') if self._include_test: argv.append('--include-test') if self._skip_recommended: argv.append('--skip-recommended') if self._include_requirements: argv.append('--include-requirements') argv.append(package) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() _deps_pkgs.extend(reversed(context.strip().split())) print_text(context, self._file, redirect=self._vflag) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') return _deps_pkgs
def _check_list(self, path): argv = [path, 'outdated'] argv.extend(self._logging_opts) argv.append('--no-parseable') argv.append('--no-json') argv.append('--global') text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.run(argv, stdout=subprocess.PIPE, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.stdout.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = list() for line in context.strip().splitlines()[1:]: name, _, want, _ = line.split(maxsplit=3) _temp_pkgs.append(f'{name}@{want}') self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _print_dependency_text(package, dependencies): def _list_dependency(dependencies): _list_pkgs = list() for package, deps_pkgs in dependencies.items(): _list_pkgs.append(package) _list_pkgs.extend(_list_dependency(deps_pkgs)) return _list_pkgs _list_pkgs = list() for item in reversed(_list_dependency(dependencies)): if item in _list_pkgs: continue _list_pkgs.append(item) if not self._topological: _list_pkgs.sort() if self._qflag: if _list_pkgs: print_term(f"{package}: {' '.join(_list_pkgs)}", self._file) else: print_term(f"{package} (independent)", self._file) else: print_text(os.linesep.join(_list_pkgs), self._file)
def _check_list(self, path): text = f'Checking outdated {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'outdated'] argv.extend(self._logging_opts) args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.SubprocessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) _temp_pkgs = dict() for line in filter(None, context.strip().splitlines()): match = re.match(r'(?P<code>\d{9}) (?P<name>.*?) \(.+?\)', line) if match is None: continue _temp_pkgs[match.group('name')] = match.group('code') self._var__temp_pkgs = set(_temp_pkgs.keys()) # pylint: disable=attribute-defined-outside-init self._ver__dict_pkgs = _temp_pkgs # pylint: disable=attribute-defined-outside-init finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n')
def _exhaust_check(self, path): text = f'Checking outdated {self.desc[1]} exclusively' print_info(text, self._file, redirect=self._vflag) argv = ['brew', 'cask', 'outdated', '--exhaust'] if self._quiet: argv.append('--quiet') if self._verbose: argv.append('--verbose') argv.extend(self._logging_opts) print_scpt(' '.join(argv), self._file, redirect=self._vflag) text = f'Listing installed {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) argv = [path, 'cask', 'list'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) _list_pkgs = set() else: context = proc.decode() _list_pkgs = set(context.split()) print_text(context, self._file, redirect=self._vflag) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') text = f'Fetching Homebrew prefix' print_info(text, self._file, redirect=self._vflag) argv = [path, '--prefix'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') fail = False try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) self._var__temp_pkgs = set() # pylint: disable=attribute-defined-outside-init fail = True else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) prefix = context.strip() finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') if fail: return text = f'Checking versions of installed {self.desc[1]}' print_info(text, self._file, redirect=self._vflag) _temp_pkgs = list() for cask in _list_pkgs: argv = [path, 'cask', 'info', cask] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) version = context.split(maxsplit=2)[1] installed = os.path.join(prefix, 'Caskroom', cask, version) if os.path.isdir(installed): _temp_pkgs.append(cask) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') self._var__temp_pkgs = set(_temp_pkgs) # pylint: disable=attribute-defined-outside-init max_len = len(max(_temp_pkgs, key=len)) context = os.linesep.join( textwrap.wrap( ' '.join( map(lambda s: s.ljust(max_len), self._var__temp_pkgs)), length)) print_scpt(f'{path} cask outdated list', self._file, redirect=self._vflag) print_text(context, self._file, redirect=self._vflag)
def install(argv=None): # parse args & set context redirection flags args = parse_args(argv) quiet = args.quiet verbose = (args.quiet or not args.verbose) # parse config & change environ config = parse_config(quiet, verbose) os.environ['SUDO_ASKPASS'] = config['Miscellaneous']['askpass'] # fetch current time today = datetime.datetime.today() logdate = datetime.date.strftime(today, r'%y%m%d') logtime = datetime.date.strftime(today, r'%H%M%S') # mkdir for logs logpath = pathlib.Path( os.path.join(config['Path']['logdir'], 'install', logdate)) logpath.mkdir(parents=True, exist_ok=True) # prepare command paras filename = os.path.join(logpath, f'{logtime}-{uuid.uuid4()!s}.log') os.environ['MACDAILY_LOGFILE'] = filename confirm = config['Miscellaneous']['confirm'] askpass = config['Miscellaneous']['askpass'] timeout = config['Miscellaneous']['limit'] disk_dir = config['Path']['arcdir'] brew_renew = None # record program status text = f'{bold}{green}|🚨|{reset} {bold}Running MacDaily version {__version__}{reset}' print_term(text, filename, redirect=quiet) record(filename, args, today, config, redirect=verbose) # ask for password text = f'{bold}{purple}|🔑|{reset} {bold}Your {under}sudo{reset}{bold} password may be necessary{reset}' print_term(text, filename, redirect=quiet) password = get_pass(askpass) cmd_list = list() for mode in {'apm', 'brew', 'cask', 'gem', 'mas', 'npm', 'pip', 'system'}: # skip disabled commands if not config['Mode'].get(mode, False): text = f'macdaily-install: {yellow}{mode}{reset}: command disabled' print_term(text, filename, redirect=verbose) continue # skip commands with no package spec packages = getattr(args, f'{mode}_pkgs', list()) namespace = getattr(args, mode, None) if not (packages or namespace): text = f'macdaily-install: {yellow}{mode}{reset}: nothing to install' print_term(text, filename, redirect=verbose) continue # update package specifications if namespace is None: namespace = dict(vars(args), packages=list()) namespace['packages'].extend(packages) # check master controlling flags if args.yes: namespace['yes'] = True if args.quiet: namespace['quiet'] = True if args.verbose: namespace['verbose'] = True if args.no_cleanup: namespace['no_cleanup'] = True # run command cmd_cls = globals()[f'{mode.capitalize()}Install'] command = cmd_cls(make_namespace(namespace), filename, timeout, confirm, askpass, password, disk_dir, brew_renew) # record command cmd_list.append(command) brew_renew = command.time archive = None if not args.no_cleanup: archive = make_archive(config, 'install', today, quiet=quiet, verbose=verbose, logfile=filename) text = f'{bold}{green}|📖|{reset} {bold}MacDaily report of install command{reset}' print_term(text, filename, redirect=quiet) for command in cmd_list: desc = make_description(command) pkgs = f'{reset}{bold}, {green}'.join(command.packages) fail = f'{reset}{bold}, {red}'.join(command.failed) if pkgs: flag = (len(pkgs) == 1) text = f'Installed following {under}{desc(flag)}{reset}{bold}: {green}{pkgs}{reset}' print_misc(text, filename, redirect=quiet) else: text = f'No {under}{desc(False)}{reset}{bold} installed' print_misc(text, filename, redirect=quiet) if fail: flag = (len(fail) == 1) text = f'Installation of following {under}{desc(flag)}{reset}{bold} failed: {red}{fail}{reset}' print_misc(text, filename, redirect=quiet) else: verb, noun = ('s', '') if len(fail) == 1 else ('', 's') text = f'All {under}{desc(False)}{reset}{bold} installation{noun} succeed{verb}' print_misc(text, filename, redirect=verbose) if archive: formatted_list = f'{reset}{bold}, {under}'.join(archive) text = ( f'Archived following ancient logs: {under}{formatted_list}{reset}') print_misc(text, filename, redirect=quiet) if len(cmd_list) == 0: # pylint: disable=len-as-condition text = f'macdaily: {purple}install{reset}: no packages installed' print_term(text, filename, redirect=quiet) if args.show_log: try: subprocess.check_call([ 'open', '-a', '/Applications/Utilities/Console.app', filename ]) except subprocess.CalledProcessError: print_text(traceback.format_exc(), filename, redirect=verbose) print( f'macdaily: {red}install{reset}: cannot show log file {filename!r}', file=sys.stderr) mode_lst = [command.mode for command in cmd_list] mode_str = ', '.join(mode_lst) if mode_lst else 'none' text = ( f'{bold}{green}|🍺|{reset} {bold}MacDaily successfully performed install process ' f'for {mode_str} package managers{reset}') print_term(text, filename, redirect=quiet)
def _proc_cleanup(self): if self._no_cleanup: return text = 'Pruning caches and archives' print_info(text, self._file, redirect=self._qflag) if not os.path.isdir(self._disk_dir): text = ( f'macdaily-{self.cmd}: {yellow}cask{reset}: ' f'archive directory {bold}{self._disk_dir}{reset} not found') print_term(text, self._file, redirect=self._vflag) return argv = ['brew', 'cask', 'cleanup'] if self._verbose: argv.append('--verbose') if self._quiet: argv.append('--quiet') print_scpt(' '.join(argv), self._file, redirect=self._qflag) path_cask = os.path.join(self._disk_dir, 'Homebrew', 'Cask') path_down = os.path.join(self._disk_dir, 'Homebrew', 'download') pathlib.Path(path_cask).mkdir(parents=True, exist_ok=True) pathlib.Path(path_down).mkdir(parents=True, exist_ok=True) for path in self._exec: argv = [path, '--cache'] args = ' '.join(argv) print_scpt(args, self._file, redirect=self._vflag) with open(self._file, 'a') as file: file.write(f'Script started on {date()}\n') file.write(f'command: {args!r}\n') fail = False try: proc = subprocess.check_output(argv, stderr=make_stderr(self._vflag)) except subprocess.CalledProcessError: print_text(traceback.format_exc(), self._file, redirect=self._vflag) fail = True else: context = proc.decode() print_text(context, self._file, redirect=self._vflag) finally: with open(self._file, 'a') as file: file.write(f'Script done on {date()}\n') if fail: continue cache = context.strip() if os.path.isdir(cache): argv = [path, 'cask', 'caches', 'archive'] if self._verbose: argv.append('--verbose') if self._quiet: argv.append('--quiet') print_scpt(' '.join(argv), self._file, redirect=self._qflag) file_list = list() link_list = glob.glob(os.path.join(cache, 'Cask/*')) cask_list = [os.path.realpath(name) for name in link_list] for link in link_list: file_list.append(link) try: shutil.move(link, path_cask) except (shutil.Error, FileExistsError): os.remove(link) for cask in filter( lambda p: os.path.splitext(p)[1] != '.incomplete', cask_list): try: shutil.move(cask, path_down) except (shutil.Error, FileExistsError): os.remove(cask) file_list.append(cask) print_text(os.linesep.join(sorted(file_list)), self._file, redirect=self._vflag)