Skip to content

Commit

Permalink
add option to install script to install globally
Browse files Browse the repository at this point in the history
  • Loading branch information
ITProKyle committed Feb 7, 2025
1 parent da6b93b commit 66f49c8
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 31 deletions.
4 changes: 4 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"recommendations": [
"DavidAnson.vscode-markdownlint",
"charliermarsh.ruff",
"editorconfig.editorconfig",
"ms-python.python",
"ms-python.vscode-pylance",
"redhat.vscode-yaml",
"streetsidesoftware.code-spell-checker",
"tamasfe.even-better-toml"
Expand Down
19 changes: 18 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
{
"cSpell.enabled": true
"[python]": {
"editor.codeActionsOnSave": {
"source.fixAll.ruff": "explicit",
"source.organizeImports": "always"
},
"editor.defaultFormatter": "charliermarsh.ruff",
"editor.detectIndentation": false,
"editor.formatOnSave": true,
"editor.insertSpaces": true,
"editor.rulers": [
81,
88,
100
],
"editor.tabSize": 4
},
"cSpell.enabled": true,
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/"
}
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ help: ## show this message

fix: fix-ruff run-pre-commit ## run all automatic fixes

fix-formatting: ## automatically fix ruff formatting issues
@poetry run ruff format .

fix-imports: ## automatically fix all import sorting errors
@poetry run ruff check . --fix-only --fixable I001

fix-ruff: ## automatically fix everything ruff can fix (implies fix-imports)
fix-ruff: fix-formatting ## automatically fix everything ruff can fix (implies fix-imports)
@poetry run ruff check . --fix-only

fix-md: ## automatically fix markdown format errors
Expand All @@ -38,6 +41,7 @@ lint-pyright: ## run pyright

lint-ruff: ## run ruff
@echo "Running ruff... If this fails, run 'make fix-ruff' to resolve some error automatically, other require manual action."
@poetry run ruff format . --diff
@poetry run ruff check .
@echo ""

Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ To install a pre-release version of OI, the `--allow-prereleases` flag can be pr
curl -sSL https://raw.githubusercontent.com/finleyfamily/oi/refs/heads/master/install.py | python3 - --allow-prereleases
```

To install globally for all users, the `--global` option can be passed to the script.
This will install OI to `/usr/local/` rather than `$HOME/.local`.

```console
curl -sSL https://raw.githubusercontent.com/finleyfamily/oi/refs/heads/master/install.py | sudo python3 - --global
curl -sSL https://raw.githubusercontent.com/finleyfamily/oi/refs/heads/master/install.py | sudo python3 - -g
```

By default the `.tar.gz` artifact of OI is installed.
If perferred, the `.zip` artifact can be used by passing `--artifact-type zip` to the script.

Expand Down
54 changes: 26 additions & 28 deletions install.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ def __init__(
*,
allow_prereleases: bool = False,
force: bool = False,
global_install: bool = False,
version: str | None = None,
) -> None:
"""Instantiate class.
Expand All @@ -239,12 +240,14 @@ def __init__(
when a version is not explicitly provided.
force: Always perform the install, even if the requested version is
detected as the currently installed version.
global_install: Install globally for all users.
version: Version to install from GitHub releases.
"""
self._version = version
self._allow_prereleases = allow_prereleases
self._force = force
self.global_install = global_install

@property
def allows_prereleases(self) -> bool:
Expand All @@ -254,7 +257,7 @@ def allows_prereleases(self) -> bool:
@cached_property
def bin_dir(self) -> Path:
"""User's bin directory."""
rv = Path.home() / ".local/bin"
rv = Path("/usr/local/bin") if self.global_install else Path.home() / ".local/bin"
rv.mkdir(exist_ok=True, parents=True)
return rv

Expand All @@ -270,7 +273,7 @@ def current_version(self) -> tuple[str, str, str, str, str, str, str, str] | Non
@cached_property
def lib_dir(self) -> Path:
"""User's lib directory."""
rv = Path.home() / ".local/lib"
rv = Path("/usr/local/lib") if self.global_install else Path.home() / ".local/lib"
rv.mkdir(exist_ok=True, parents=True)
return rv

Expand All @@ -279,9 +282,7 @@ def releases(self) -> list[dict[str, Any]]:
"""List of available releases."""
metadata = self._get(f"{self.API_URL}/releases")

def _compare_versions(
x: dict[str, Any], y: dict[str, Any]
) -> Literal[-1, 0, 1]:
def _compare_versions(x: dict[str, Any], y: dict[str, Any]) -> Literal[-1, 0, 1]:
mx = self.VERSION_REGEX.match(x["tag_name"])
my = self.VERSION_REGEX.match(y["tag_name"])

Expand Down Expand Up @@ -366,14 +367,10 @@ def display_pre_message(self) -> None:
)
)

def download_release_artifact(
self, artifact: ReleaseArtifact, tmp_dir: Path
) -> Path:
def download_release_artifact(self, artifact: ReleaseArtifact, tmp_dir: Path) -> Path:
"""Download a release artifact."""
self.write_stdout(
"Downloading from {}...".format(
colorize("info", artifact["browser_download_url"])
)
"Downloading from {}...".format(colorize("info", artifact["browser_download_url"]))
)
out_file = tmp_dir / artifact["name"]
urlretrieve(artifact["browser_download_url"], out_file) # noqa: S310
Expand All @@ -386,9 +383,7 @@ def find_oi_release_artifact(
release = self._get(f"{self.API_URL}/releases/tags/v{version.lstrip('v')}")
asset: ReleaseArtifact | None = None
mime_type = (
"application/zip"
if artifact_type == "zip"
else f"application/x-{artifact_type}"
"application/zip" if artifact_type == "zip" else f"application/x-{artifact_type}"
)
for i in release["assets"]:
if i["content_type"] == mime_type:
Expand Down Expand Up @@ -436,7 +431,7 @@ def get_version(
and not self._force
):
self.write_stdout(
f'The latest version ({colorize("b", release["tag_name"])}) is already installed'
f"The latest version ({colorize('b', release['tag_name'])}) is already installed"
)

return None, self.current_version
Expand All @@ -455,18 +450,14 @@ def install(self, artifact_type: Literal["gtar", "zip"] = "gtar") -> int:
return 0

self.write_stdout(
"Installing {} ({})".format(
colorize("info", "oi"), colorize("info", version)
)
"Installing {} ({})".format(colorize("info", "oi"), colorize("info", version))
)

with tempfile.TemporaryDirectory() as tmp_dir:
extracted = (
ArchiveExtractor(
self.download_release_artifact(
self.find_oi_release_artifact(
artifact_type=artifact_type, version=version
),
self.find_oi_release_artifact(artifact_type=artifact_type, version=version),
Path(tmp_dir),
)
).extract()
Expand All @@ -489,9 +480,7 @@ def uninstall(self) -> int:
"""Uninstall oi."""
lib_dir = self.lib_dir / "oi"
if not lib_dir.exists():
self.write_stdout(
"{} is not currently installed.".format(colorize("info", "oi"))
)
self.write_stdout("{} is not currently installed.".format(colorize("info", "oi")))
return 1

if self.current_version:
Expand Down Expand Up @@ -555,6 +544,14 @@ def main() -> int:
dest="force",
help="Install on top of existing version.",
)
parser.add_argument(
"-g",
"--global",
action="store_true",
default=False,
dest="global_install",
help="Install globally for all users. NOTE: Should be run with elevated privileges (e.g. 'sudo').",
)
parser.add_argument(
"-p",
"--allow-prereleases",
Expand All @@ -576,7 +573,10 @@ def main() -> int:
args = parser.parse_args()

installer = Installer(
version=args.version, allow_prereleases=args.allow_prereleases, force=args.force
allow_prereleases=args.allow_prereleases,
force=args.force,
global_install=args.global_install,
version=args.version,
)

try:
Expand All @@ -586,9 +586,7 @@ def main() -> int:
except Exception as err: # noqa: BLE001
import traceback

installer.write_stdout(
colorize("error", "".join(traceback.format_exception(err)))
)
installer.write_stdout(colorize("error", "".join(traceback.format_exception(err))))
installer.write_stdout(colorize("error", "Installation failed!"))
return 1

Expand Down
8 changes: 7 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@ venv = ".venv"

[tool.ruff] # https://docs.astral.sh/ruff/settings/#top-level
force-exclude = true
line-length = 120
line-length = 100
show-fixes = true
target-version = "py310"

[tool.ruff.format] # https://docs.astral.sh/ruff/settings/#format
docstring-code-format = true

[tool.ruff.lint] # https://docs.astral.sh/ruff/settings/#lint
ignore = [
"COM812", # Trailing comma missing
Expand Down Expand Up @@ -71,6 +74,9 @@ runtime-evaluated-base-classes = [
"pydantic.BeforeValidator",
]

[tool.ruff.lint.pycodestyle] # https://docs.astral.sh/ruff/settings/#lint_pycodestyle_max-line-length
max-line-length = 140

[tool.ruff.lint.pydocstyle] # https://docs.astral.sh/ruff/settings/#lintpydocstyle
convention = "google"

Expand Down

0 comments on commit 66f49c8

Please sign in to comment.