Merge pull request #225 from aminya/pipx [skip ci]

fix: install to the user home when using pipx as sudo
This commit is contained in:
Amin Yahyaabadi 2024-01-24 15:32:19 -08:00 committed by GitHub
commit 5876082b0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 180 additions and 79 deletions

View File

@ -26,12 +26,11 @@ words:
- copr
- CPATH
- Cppcheck
- nodistro
- dearmor
- CPPFLAGS
- cpprc
- Cpython
- DCMAKE
- dearmor
- deps
- devel
- DVCPKG
@ -63,6 +62,7 @@ words:
- mxschmitt
- nala
- noconfirm
- nodistro
- noprogressbar
- nothrow
- npmrc
@ -84,6 +84,7 @@ words:
- Trofimovich
- tsbuildinfo
- ucrt
- untildified
- untildify
- upleveled
- vbatts
@ -91,6 +92,7 @@ words:
- VCPKG
- vcvarsall
- venv
- venvs
- visualc
- visualcpp
- vsversion

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -103,6 +103,7 @@
"is-url-online": "^1.5.0",
"jest": "^29.7.0",
"micro-memoize": "^4.1.2",
"mkdirp": "^3.0.1",
"mri": "^1.2.0",
"msvc-dev-cmd": "github:aminya/msvc-dev-cmd#97843d525947e3f3776ee359b597316909754c4d",
"npm-check-updates": "^16.14.12",

View File

@ -18,13 +18,23 @@ npm install --save untildify-user
<!-- INSERT GENERATED DOCS START -->
### `userHomeDir` (function)
**returns:** string
### `untildifyUser` (function)
Replaces a tilde with the user's home directory
**Parameters:**
- path (`string`)
- path (`string`) - The path to untildify
**returns:** any
**returns:** string
```tsx
UntildifyUser("~/foo") // /home/user/foo
```
<!-- INSERT GENERATED DOCS END -->

View File

@ -11,8 +11,7 @@
"build": "tsc"
},
"dependencies": {
"admina": "1.0.1",
"untildify": "^5.0.0"
"admina": "1.0.1"
},
"keywords": [
"tilde",

View File

@ -1,16 +1,39 @@
import { join } from "path"
import untildify from "untildify"
import { isSudo } from "admina"
import { homedir } from "os"
export function untildifyUser(path: string) {
if (isSudo() && typeof process.env.SUDO_USER === "string") {
export function userHomeDir() {
if (isSudo() && typeof process.env.SUDO_USER === "string" && process.env.SUDO_USER !== "") {
// use the user profile even if root
if (process.platform === "darwin") {
return join("/Users/", process.env.SUDO_USER, path)
return join("/Users/", process.env.SUDO_USER)
} else {
return join("/home/", process.env.SUDO_USER, path)
return join("/home/", process.env.SUDO_USER)
}
} else {
return untildify(`~/${path}`)
const maybeHomeDir = homedir()
if (maybeHomeDir === "") {
return undefined
}
return maybeHomeDir
}
}
const tildeRegex = /^~(?=$|\/|\\)/
/**
* Replaces a tilde with the user's home directory
*
* @example UntildifyUser("~/foo") // /home/user/foo
*
* @param path The path to untildify
* @returns The untildified path
*/
export function untildifyUser(path: string) {
const maybeHomeDir = userHomeDir()
if (maybeHomeDir === undefined) {
return path
}
return path.replace(tildeRegex, maybeHomeDir)
}

View File

@ -107,6 +107,9 @@ importers:
micro-memoize:
specifier: ^4.1.2
version: 4.1.2
mkdirp:
specifier: ^3.0.1
version: 3.0.1
mri:
specifier: ^1.2.0
version: 1.2.0
@ -210,9 +213,6 @@ importers:
admina:
specifier: 1.0.1
version: 1.0.1
untildify:
specifier: ^5.0.0
version: 5.0.0
packages:
@ -8131,6 +8131,12 @@ packages:
hasBin: true
dev: true
/mkdirp@3.0.1:
resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==}
engines: {node: '>=10'}
hasBin: true
dev: true
/mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@ -10308,11 +10314,6 @@ packages:
engines: {node: '>=8'}
dev: true
/untildify@5.0.0:
resolution: {integrity: sha512-bOgQLUnd2G5rhzaTvh1VCI9Fo6bC5cLTpH17T5aFfamyXFYDbbdzN6IXdeoc3jBS7T9hNTmJtYUzJCJ2Xlc9gA==}
engines: {node: '>=16'}
dev: false
/update-browserslist-db@1.0.13(browserslist@4.22.2):
resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==}
hasBin: true

View File

@ -81,14 +81,14 @@ async function getCmake() {
if (cmake === null) {
const { binDir } = await setupCmake(
getVersion("cmake", undefined, await ubuntuVersion()),
join(untildifyUser(""), "cmake"),
join(untildifyUser("~"), "cmake"),
"",
)
cmake = join(binDir, "cmake")
}
const ninja = which.sync("ninja", { nothrow: true })
if (ninja === null) {
await setupNinja(getVersion("ninja", undefined, await ubuntuVersion()), join(untildifyUser(""), "ninja"), "")
await setupNinja(getVersion("ninja", undefined, await ubuntuVersion()), join(untildifyUser("~"), "ninja"), "")
}
return cmake
}

View File

@ -39,7 +39,7 @@ async function main(args: string[]): Promise<number> {
const arch = opts.architecture ?? process.arch
// the installation dir for the tools that are downloaded directly
const setupCppDir = process.env.SETUP_CPP_DIR ?? untildifyUser("")
const setupCppDir = process.env.SETUP_CPP_DIR ?? untildifyUser("~")
// report messages
const successMessages: string[] = []

View File

@ -17,6 +17,12 @@ describe("setup-nala", () => {
afterAll(() => {
// remove nala to run the rest of the tests with apt-get
execRootSync("apt-get", ["remove", "-y", "nala"])
execRootSync("apt-get", ["remove", "-y", "nala-legacy"])
try {
execRootSync("apt-get", ["remove", "-y", "nala-legacy"])
} catch (err) {
// ignore
console.error(err)
}
})
})

View File

@ -28,7 +28,8 @@ describe("setup-python", () => {
const installInfo = await setupPython(getVersion("python", "true", await ubuntuVersion()), directory, process.arch)
await testBin("python", ["--version"], installInfo.binDir)
const python = process.platform === "darwin" ? "python3" : "python"
await testBin(python, ["--version"], installInfo.binDir)
})
afterAll(async () => {

View File

@ -100,7 +100,7 @@ export async function addPath(path: string) {
}
}
export const cpprc_path = untildifyUser(".cpprc")
export const cpprc_path = untildifyUser("~/.cpprc")
async function addEnvSystem(name: string, valGiven: string | undefined, options: AddEnvOptions) {
const val = valGiven ?? ""
@ -188,12 +188,12 @@ export async function setupCppInProfile() {
try {
// source cpprc in .profile
const profile_path = untildifyUser(".profile")
const profile_path = untildifyUser("~/.profile")
appendFileSync(profile_path, source_cpprc_string)
info(`${source_cpprc_string} was added to ${profile_path}`)
// source cpprc in .bashrc too
const bashrc_path = untildifyUser(".bashrc")
const bashrc_path = untildifyUser("~/.bashrc")
appendFileSync(bashrc_path, source_cpprc_string)
info(`${source_cpprc_string} was added to ${bashrc_path}`)
} catch (err) {

View File

@ -15,6 +15,8 @@ import { hasDnf } from "../env/hasDnf"
import { setupDnfPack } from "./setupDnfPack"
import { isUbuntu } from "../env/isUbuntu"
import { setupAptPack } from "./setupAptPack"
import { untildifyUser } from "untildify-user"
import { mkdirp } from "mkdirp"
export type SetupPipPackOptions = {
/** Whether to use pipx instead of pip */
@ -56,8 +58,17 @@ export async function setupPipPackWithPython(
const upgradeFlag = upgrade ? (isPipx ? ["upgrade"] : ["install", "--upgrade"]) : ["install"]
const userFlag = !isPipx && user ? ["--user"] : []
const env = process.env
if (isPipx && user) {
// install to user home
env.PIPX_HOME = await getPipxHome()
env.PIPX_BIN_DIR = await getPipxBinDir()
}
execaSync(givenPython, ["-m", pip, ...upgradeFlag, ...userFlag, nameAndVersion], {
stdio: "inherit",
env,
})
} catch (err) {
info(`Failed to install ${name} via ${pip}: ${err}.`)
@ -83,6 +94,53 @@ export async function hasPipx(givenPython: string) {
return (await execa(givenPython, ["-m", "pipx", "--help"], { stdio: "ignore", reject: false })).exitCode === 0
}
async function getPipxHome_raw() {
let pipxHome = process.env.PIPX_HOME
if (pipxHome !== undefined) {
return pipxHome
}
// Based on https://pipx.pypa.io/stable/installation/
const compatHome = untildifyUser("~/.local/pipx")
if (await pathExists(compatHome)) {
return compatHome
}
switch (process.platform) {
case "win32": {
pipxHome = untildifyUser("~/AppData/Local/pipx")
break
}
case "darwin": {
pipxHome = untildifyUser("~/Library/Application Support/pipx")
break
}
default: {
pipxHome = untildifyUser("~/.local/share/pipx")
break
}
}
await mkdirp(pipxHome)
await mkdirp(join(pipxHome, "trash"))
await mkdirp(join(pipxHome, "shared"))
await mkdirp(join(pipxHome, "venv"))
return pipxHome
}
const getPipxHome = memoize(getPipxHome_raw, { isPromise: true })
async function getPipxBinDir_raw() {
if (process.env.PIPX_BIN_DIR !== undefined) {
return process.env.PIPX_BIN_DIR
}
const pipxBinDir = untildifyUser("~/.local/bin")
await addPath(pipxBinDir)
await mkdirp(pipxBinDir)
return pipxBinDir
}
const getPipxBinDir = memoize(getPipxBinDir_raw, { isPromise: true })
async function getPython_raw(): Promise<string> {
const pythonBin = (await setupPython(getVersion("python", undefined, await ubuntuVersion()), "", process.arch)).bin
if (pythonBin === undefined) {