def mv(sample, target): """Move a test sample (and its baseline) to a new place""" new_category, _, new_basename = target.partition("/") if "/" in new_basename: sys.exit("Invalid target '%s': use at most one / separator" % runez.red(target)) if not new_basename: new_basename = sample.basename if new_basename.endswith(".yml"): new_basename = new_basename[:-4] old_source = os.path.join(sample.category, sample.basename) new_target = os.path.join(new_category, new_basename) if old_source == new_target: print("%s is already in the right spot" % runez.bold(sample)) sys.exit(0) existing = TestSamples.get_samples(new_target + ".yml") if existing: sys.exit("There is already a sample '%s'" % runez.red(new_target)) TestSamples.move_sample_file(sample, new_category, new_basename) TestSamples.move_sample_file(sample, new_category, new_basename, kind=TestSamples.K_DESERIALIZED) TestSamples.move_sample_file(sample, new_category, new_basename, kind=TestSamples.K_TOKEN) TestSamples.clean_samples()
def perform_install(pspec, is_upgrade=False, force=False, quiet=False): """ Args: pspec (PackageSpec): Package spec to install is_upgrade (bool): If True, intent is an upgrade (not a new install) force (bool): If True, check latest version even if recently checked quiet (bool): If True, don't chatter Returns: (pickley.TrackedManifest): Manifest is successfully installed (or was already up-to-date) """ with SoftLock(pspec): started = time.time() pspec.resolve() skip_reason = pspec.skip_reason(force) if skip_reason: inform("Skipping installation of %s: %s" % (pspec.dashed, runez.bold(skip_reason))) return None manifest = pspec.get_manifest() if is_upgrade and not manifest and not quiet: abort("'%s' is not installed" % runez.red(pspec)) if not pspec.version: desired = pspec.get_desired_version_info(force=force) if desired.problem: action = "upgrade" if is_upgrade else "install" abort("Can't %s %s: %s" % (action, pspec, runez.red(desired.problem))) pspec.version = desired.version if not force and manifest and manifest.version == pspec.version and pspec.is_healthily_installed( ): if not quiet: status = "up-to-date" if is_upgrade else "installed" inform("%s v%s is already %s" % (pspec.dashed, runez.bold(pspec.version), status)) pspec.groom_installation() return manifest setup_audit_log() manifest = PACKAGER.install(pspec) if manifest and not quiet: note = " in %s" % runez.represented_duration(time.time() - started) action = "Upgraded" if is_upgrade else "Installed" if runez.DRYRUN: action = "Would state: %s" % action inform("%s %s v%s%s" % (action, pspec.dashed, runez.bold( pspec.version), runez.dim(note))) if not pspec._pickley_dev_mode: pspec.groom_installation() return manifest
def resolve(self): if not os.path.isdir(self.folder): abort("Folder %s does not exist" % runez.red(runez.short(self.folder))) req = self.requirements if not req: default_req = runez.resolved_path("requirements.txt", base=self.folder) if os.path.exists(default_req): req = [default_req] if req: req = [("-r", runez.resolved_path(r, base=self.folder)) for r in req] req = runez.flattened(req, shellify=True) req.append(self.folder) self.requirements = req self.pspec = PackageSpec(CFG, self.folder) LOG.info("Using python: %s" % self.pspec.python) if self.dist.startswith("root/"): # Special case: we're targeting 'root/...' probably for a debian, use target in that case to avoid venv relocation issues target = self.dist[4:] if os.path.isdir(target): LOG.debug("debian mode: %s -> %s", self.dist, target) self.dist = target parts = self.dist.split("/") if len(parts) <= 2: # Auto-add package name to targets of the form root/subfolder (most typical case) self.dist = os.path.join(self.dist, self.pspec.dashed)
def uninstall(all, packages): """Uninstall packages""" if packages and all: abort("Either specify packages to uninstall, or --all (but not both)") if not packages and not all: abort("Specify packages to uninstall, or --all") if packages and PICKLEY in packages: abort( "Run 'uninstall --all' if you wish to uninstall pickley itself (and everything it installed)" ) setup_audit_log() for pspec in CFG.package_specs(packages): manifest = pspec.get_manifest() if not manifest or not manifest.version: abort("%s was not installed with pickley" % runez.bold(pspec.dashed)) if manifest.entrypoints: for ep in manifest.entrypoints: runez.delete(pspec.exe_path(ep)) runez.delete(pspec.meta_path) action = "Would uninstall" if runez.DRYRUN else "Uninstalled" inform("%s %s" % (action, pspec.dashed)) if all: runez.delete(CFG.base.full_path(PICKLEY)) runez.delete(CFG.meta.path) inform("pickley is now %s" % runez.red("uninstalled"))
def base(what): """Show pickley base folder""" path = CFG.base.path if what == "bootstrap-own-wrapper": # Internal: called by bootstrap script from pickley.delivery import DeliveryMethodWrap pspec = PackageSpec(CFG, PICKLEY, version=__version__) venv = PythonVenv(pspec, create=False) wrap = DeliveryMethodWrap() wrap.install(pspec, venv, {PICKLEY: PICKLEY}) return if what: paths = { "audit": CFG.meta.full_path("audit.log"), "cache": CFG.cache.path, "config": CFG.meta.full_path("config.json"), "meta": CFG.meta.path, } paths["audit.log"] = paths["audit"] paths["config.json"] = paths["config"] path = paths.get(what) if not path: options = [runez.green(s) for s in sorted(paths)] abort("Unknown base folder reference '%s', try one of: %s" % (runez.red(what), ", ".join(options))) print(path)
def show_outcome(content, implementations, tokens=False): TestSettings.show_lines(content) for impl in implementations: assert isinstance(impl, Implementation) data = impl.get_outcome(content, tokens=tokens) impl.show_result(data, tokens=tokens) if TestSettings.profiler: return if not tokens: implementations.track_result_combination(impl, data) if implementations.combinations: matches = [] differs = [] for names, values in implementations.combinations.items(): combination = " / ".join(sorted(names, reverse=True)) if len(values) == 1: matches.append(combination) else: differs.append(combination) if matches: print("-- matches: %s" % runez.green(", ".join(sorted(matches, reverse=True)))) if differs: print("-- differs: %s" % runez.red(", ".join(sorted(differs, reverse=True))))
def find_python(self, pspec=None, fatal=True): """ Args: pspec (PackageSpec | None): Package spec, when applicable fatal (bool): If True, abort execution is no valid python could be found Returns: (runez.pyenv.PythonInstallation): Object representing python installation """ desired = self.get_value("python", pspec=pspec) desired = runez.flattened(desired, split=",") if not desired: # Edge case: configured empty python... just use invoker in that case return self.available_pythons.invoker issues = [] python = None for d in desired: python = self.available_pythons.find_python(d) if not python.problem: return python issues.append( "Python '%s' skipped: %s" % (runez.bold(runez.short(d)), runez.red(python.problem))) for i in issues: # Warn only if no python could be found at all LOG.warning(i) if fatal: abort("No suitable python installation found") return python
def install(self, pspec, venv, entry_points): """ Args: pspec (pickley.PackageSpec): Package spec this installation is for venv (pickley.package.PythonVenv): Virtual env where executables reside (DOT_META/<package>/...) entry_points (dict | list): Full path of executable to deliver (<base>/<entry_point>) """ if not pspec.is_clear_for_installation(): auto_uninstall(pspec.exe_path(pspec.dashed)) try: prev_manifest = pspec.get_manifest() for name in entry_points: src = venv.bin_path(name) dest = pspec.exe_path(name) if runez.DRYRUN: print("Would %s %s -> %s" % (self.short_name, short(dest), short(src))) continue if not os.path.exists(src): abort( "Can't %s %s -> %s: source does not exist" % (self.short_name, short(dest), runez.red(short(src)))) LOG.debug("%s %s -> %s" % (self.action, short(dest), short(src))) self._install(pspec, dest, src) manifest = pspec.save_manifest(entry_points) if not runez.DRYRUN and prev_manifest and prev_manifest.entrypoints: for old_ep in prev_manifest.entrypoints: if old_ep and old_ep not in entry_points: # Remove old entry points that are not in new manifest any more runez.delete(pspec.exe_path(old_ep)) if self.ping: # Touch the .ping file since this is a fresh install (no need to check for upgrades right away) runez.touch(pspec.ping_path) return manifest except Exception as e: abort("Failed to %s %s: %s" % (self.short_name, short(pspec), runez.red(e)))
def main(debug): """Git my dotfiles!""" global GDOTX runez.system.AbortException = SystemExit if os.geteuid() == 0: GDEnv.complain("%s was not designed to run as %s\n\n" % (runez.blue("gdot"), runez.red("root"))) GDEnv.complain("Please %s if you see a use-case for that on %s\n\n" % (runez.yellow("let us know"), GDEnv.issues_url)) sys.exit(1) GDOTX = GDotXBase() runez.log.setup(debug=debug, console_format="%(levelname)s %(message)s", locations=None, greetings=":: {argv}")
def test_uncolored(): # Verify incomplete codes are removed too assert runez.uncolored("foo-\x1b[0m z") == "foo- z" assert runez.uncolored("foo-\x1b") == "foo-" assert runez.uncolored("foo-\x1b[") == "foo-" with runez.ActivateColors(terminal.TrueColorBackend(flavor="neutral")): assert runez.uncolored(runez.red("foo")) == "foo" assert runez.color.adjusted_size("foo", 5) == 5 assert runez.color.adjusted_size(runez.red("foo"), 5) == 25 with runez.ActivateColors(terminal.Ansi16Backend(flavor="neutral")): assert runez.uncolored(None) == "None" assert runez.uncolored(" ") == " " assert runez.uncolored("foo") == "foo" assert runez.uncolored(runez.red("foo")) == "foo" assert runez.uncolored("%s - %s" % (runez.red("foo"), runez.yellow("bar"))) == "foo - bar" assert runez.color.adjusted_size("foo", 5) == 5 assert runez.color.adjusted_size(runez.red("foo"), 5) == 15
def pypi_name_problem(name): if not PypiStd.is_acceptable(name): note = None problem = "'%s' is not a valid pypi package name" % runez.red(name) if name and not name[0].isalpha(): note = "\npickley intentionally refuses to look at names that don't start with a letter" if note: note += "\nIf you think this name is legit, please submit an issue https://github.com/codrsquad/pickley/issues" problem = "%s\n%s" % (problem, note) return problem
def find_base(): base_path = runez.resolved_path(os.environ.get("PICKLEY_ROOT")) if base_path: if not os.path.isdir(base_path): abort("PICKLEY_ROOT points to non-existing directory %s" % runez.red(base_path)) return runez.resolved_path(base_path) program_path = PickleyConfig.program_path return _find_base_from_program_path(program_path) or os.path.dirname( program_path)
def freshness(self): """Short freshness overview""" result = [] if self.report._problem: result.append(runez.red(" ".join(self.report._problem))) if self.modified: result.append(runez.red(runez.plural(self.modified, "diff"))) if self.untracked: result.append(runez.orange("%s untracked" % len(self.untracked))) if self.report._note: result.append(runez.purple(" ".join(self.report._note))) if not self.report._problem and not self.report._note and self._parent.age is not None: message = "up to date" if self._parent.age > FRESHNESS_THRESHOLD: message += "*" result.append(runez.teal(message)) return ", ".join(result)
def represented(cls, value, size=runez.UNSET, stringify=runez.stringified, dt=str): if isinstance(value, NotImplementedError): if size is None: return {"_error": "not implemented"} return runez.orange("not implemented") if isinstance(value, Exception): if size is None: return {"_error": runez.short(value, size=256)} return runez.red(runez.short(value, size=size)) return runez.represented_json(value, stringify=stringify, dt=dt, keep_none=True, none_key="-null-")
def colored_key(key, indent): if (key in K_CLI or key in K_LEAVES) and indent in (1, 3): return runez.teal(key) if key in K_DIRECTIVES and indent == 1: return runez.dim(key) if key in K_GROUPS and indent == 1: return runez.purple(key) if indent == 2: return runez.bold(key) return runez.red(key)
def delivery_method_by_name(cls, name): """ Args: name (str): Name of delivery method Returns: (DeliveryMethod): Associated delivery method """ if name == "wrap": return DeliveryMethodWrap() if name == "symlink": return DeliveryMethodSymlink() return abort("Unknown delivery method '%s'" % runez.red(name))
def move_sample_file(cls, sample, new_category, new_basename, kind=None): dest = os.path.join(cls.SAMPLE_FOLDER, new_category) if not os.path.isdir(dest): sys.exit("No folder %s" % runez.red(dest)) if kind: extension = ".json" source = sample.expected_path(kind) dest = os.path.join(dest, "_xpct-%s" % kind) else: extension = ".yml" source = sample.path if os.path.isfile(source): dest = os.path.join(dest, new_basename + extension) runez.move(source, dest, logger=logging.info)
def install(pspec, ping=True): delivery = DeliveryMethod.delivery_method_by_name(pspec.settings.delivery) delivery.ping = ping args = [pspec.specced] if pspec.folder: args = [pspec.folder] elif pspec._pickley_dev_mode: args = ["-e", pspec._pickley_dev_mode] # pragma: no cover, convenience case for running pickley from .venv/ venv = PythonVenv(pspec) venv.pip_install(*args) contents = PackageContents(venv, pspec) if not contents.entry_points: runez.delete(pspec.meta_path) abort("Can't install '%s', it is %s" % (runez.bold(pspec.dashed), runez.red("not a CLI"))) return delivery.install(pspec, venv, contents.entry_points)
def report(self, fastest=None, indent=""): message = "%s%s: " % (indent, self.name) if self.error: return "%s%s" % (message, TestSettings.represented(self.error, size=-len(message))) if self.seconds is None: return "%s%s" % (message, runez.red("no result")) info = "" if fastest and self.seconds and fastest.seconds and self.seconds != fastest.seconds: info = runez.dim(" [x %.1f]" % (self.seconds / fastest.seconds)) unit = u"μ" x = self.seconds / self.iterations * 1000000 if x >= 999: x = x / 1000 unit = "m" if x >= 999: x = x / 1000 unit = "s" return "%s%s: %.3f %ss/i%s" % (indent, self.name, x, unit, info)
def cmd_progress_bar(): """Show a progress bar sample""" names = AsciiAnimation.available_names() parser = runez.cli.parser() parser.add_argument( "--delay", "-d", type=float, default=100.0, help="Time in milliseconds to sleep between iterations.") parser.add_argument("--iterations", "-i", type=int, default=100, help="Number of iterations to run.") parser.add_argument("--log-every", "-l", type=int, default=5, help="Log a message every N iterations.") parser.add_argument("--spinner", "-s", choices=names, default=None, help="Pick spinner to use.") parser.add_argument( "--sleep", type=float, default=None, help= "Extra sleep when done, useful for inspecting animation a bit further." ) parser.add_argument( "--no-spinner", "-n", action="store_true", help="Useful to compare CPU usage with and without spinner.") parser.add_argument("--verbose", "-v", action="store_true", help="More chatty output.") parser.add_argument("name", nargs="*", help="Names of modules to show (by default: all).") args = parser.parse_args() process = None try: import psutil process = psutil.Process(os.getpid()) process.cpu_percent() except ImportError: # pragma: no cover pass runez.log.setup(console_format="%(levelname)s %(message)s", console_level=logging.INFO, trace="RUNEZ_DEBUG") if not args.no_spinner: runez.log.progress.start(frames=args.spinner, max_columns=40, spinner_color=runez.yellow) logger = logging.info if args.verbose else logging.debug for i in runez.ProgressBar(range(args.iterations)): i += 1 if args.log_every and i % args.log_every == 0: logger("Running\niteration %s %s", runez.red(i), "-" * 50) logger = logging.debug else: runez.log.trace("At iteration %s" % i) if args.verbose and i % 10 == 0: # pragma: no cover print("iteration %s" % runez.bold(i)) if i == 42: # pragma: no cover runez.log.progress.show( "some progress msg" ) # debug() and trace() messages don't appear any more after this for _ in runez.ProgressBar(range(10)): time.sleep(0.1) time.sleep(args.delay / 1000) msg = "done" if process: cpu_usage = ("%.2f" % process.cpu_percent()).rstrip("0") msg += " (%s%% CPU usage)" % cpu_usage print(msg) if args.sleep: runez.log.progress.show(msg) time.sleep(args.sleep)
def cmd_import_speed(): """Show average import time of top-level python packages installed in this venv""" parser = runez.cli.parser() parser.add_argument("--all", action="store_true", help="Show all.") parser.add_argument("--border", choices=NAMED_BORDERS, default="reddit", help="Use custom border.") parser.add_argument("--iterations", "-i", type=int, default=3, help="Number of measurements to average.") parser.add_argument("name", nargs="*", help="Names of modules to show (by default: all).") args = parser.parse_args() names = runez.flattened(args.name, split=",") if args.all: names.extend(_all_deps()) if not names: sys.exit("Please specify module names, or use --all") names = sorted(set(names)) times = [] fastest = None slowest = None for name in names: t = ImportTime(name, iterations=args.iterations) times.append(t) if t.cumulative is None: continue if fastest is None or (t.cumulative < fastest.cumulative): fastest = t if slowest is None or t.cumulative > slowest.cumulative: slowest = t table = PrettyTable("Module,-X cumulative,Elapsed,Vs fastest,Note", border=args.border) table.header[3].align = "center" mid = _get_mid(times) or 0 for t in sorted(times): if t.cumulative is None: c = e = f = None else: factor = t.elapsed / fastest.elapsed c = runez.represented_duration(t.cumulative / 1000000, span=-2) e = runez.represented_duration(t.elapsed, span=-2) f = "x%.2f" % factor if t is fastest: f = "" elif t is slowest: f = runez.red(f) elif t.elapsed and t.elapsed > mid: f = runez.orange(f) table.add_row(t.module_name, c, e, f, t.problem or "") print(table)
def test_colors(): dim = runez.color.style.dim assert runez.color.cast_style(dim) is dim assert runez.color.cast_style(runez.dim) is runez.dim assert runez.color.cast_style("dim") is dim assert runez.color.cast_color(dim) is dim assert runez.color.cast_color("dim") is dim assert runez.color.cast_color("blue") is runez.color.fg.blue msg1 = dim("hi") msg2 = runez.colored("hi", "dim") assert msg1 == msg2 with pytest.raises(ValueError): runez.color.cast_style("foo") assert not runez.color.is_coloring() with runez.ActivateColors(terminal.Ansi16Backend): # Check that backend can be passed as class (flavor auto-determined in that case) assert runez.color.is_coloring() assert "ansi16" in runez.color.backend.name msg1 = runez.dim("hi") msg2 = runez.colored("hi", "dim") assert msg1 == msg2 assert not runez.color.is_coloring() with runez.ActivateColors(terminal.Ansi16Backend(flavor="neutral")): assert runez.color.is_coloring() assert runez.red(None) == "\x1b[31mNone\x1b[39m" assert runez.blue("") == "" assert runez.plain("hello") == "hello" assert runez.yellow("hello") == "\x1b[33mhello\x1b[39m" assert runez.yellow("hello", size=4) == "\x1b[33mh...\x1b[39m" assert runez.bold(1) == "\x1b[1m1\x1b[22m" assert runez.color.bg.get(None) is None assert runez.color.bg.get("blue") is runez.color.bg.blue assert runez.dim("") == "" assert runez.dim("hello", size=4) == "\x1b[2mh...\x1b[22m" # Verify unicode char 'μ' from represented_duration() works assert "foo: %s" % runez.dim(runez.represented_duration(0.010049)) == "foo: \x1b[2m10 ms 49 μs\x1b[22m" assert "foo: %s" % runez.blue(runez.represented_duration(0.010049)) == "foo: \x1b[34m10 ms 49 μs\x1b[39m" assert not runez.color.is_coloring() assert runez.black("") == "" assert runez.blue("") == "" assert runez.brown("") == "" assert runez.gray("") == "" assert runez.green("") == "" assert runez.orange("") == "" assert runez.plain("hello") == "hello" assert runez.purple("") == "" assert runez.red(None) == "None" assert runez.teal("") == "" assert runez.white("") == "" assert runez.yellow("hello") == "hello" assert runez.blink("hello") == "hello" assert runez.bold(1) == "1" assert runez.dim("") == "" assert runez.invert("") == "" assert runez.italic("") == "" assert runez.strikethrough("") == "" assert runez.underline("") == "" assert str(runez.color.fg.black) == "black"
def abort(self, message): self.complain(message) instructions = ISSUE_TEMPLATE.format(report=runez.red("report"), diagnostics=self.diagnostics(), issues_url=GDEnv.issues_url) self.complain(instructions) sys.exit(1)
def validate(self, require_installed=True): problem = self.problem(require_installed) if problem: sys.stderr.write("%s\n" % runez.red(problem)) sys.exit(1)
def not_implemented(): caller = runez.system.find_caller_frame() cmd = "gdot %s" % caller.f_code.co_name sys.exit("%s is not yet implemented" % runez.red(cmd))