Skip to content

Commit 5876082

Browse files
authored
Merge pull request #225 from aminya/pipx [skip ci]
fix: install to the user home when using pipx as sudo
2 parents f55ff60 + a486582 commit 5876082

File tree

18 files changed

+180
-79
lines changed

18 files changed

+180
-79
lines changed

cspell.config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@ words:
2626
- copr
2727
- CPATH
2828
- Cppcheck
29-
- nodistro
30-
- dearmor
3129
- CPPFLAGS
3230
- cpprc
3331
- Cpython
3432
- DCMAKE
33+
- dearmor
3534
- deps
3635
- devel
3736
- DVCPKG
@@ -63,6 +62,7 @@ words:
6362
- mxschmitt
6463
- nala
6564
- noconfirm
65+
- nodistro
6666
- noprogressbar
6767
- nothrow
6868
- npmrc
@@ -84,13 +84,15 @@ words:
8484
- Trofimovich
8585
- tsbuildinfo
8686
- ucrt
87+
- untildified
8788
- untildify
8889
- upleveled
8990
- vbatts
9091
- vcpkg
9192
- VCPKG
9293
- vcvarsall
9394
- venv
95+
- venvs
9496
- visualc
9597
- visualcpp
9698
- vsversion

dist/actions/setup-cpp.js

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/actions/setup-cpp.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/legacy/setup-cpp.js

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/legacy/setup-cpp.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/modern/setup-cpp.js

Lines changed: 16 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/modern/setup-cpp.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@
103103
"is-url-online": "^1.5.0",
104104
"jest": "^29.7.0",
105105
"micro-memoize": "^4.1.2",
106+
"mkdirp": "^3.0.1",
106107
"mri": "^1.2.0",
107108
"msvc-dev-cmd": "github:aminya/msvc-dev-cmd#97843d525947e3f3776ee359b597316909754c4d",
108109
"npm-check-updates": "^16.14.12",

packages/untildify-user/README.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,23 @@ npm install --save untildify-user
1818

1919
<!-- INSERT GENERATED DOCS START -->
2020

21+
### `userHomeDir` (function)
22+
23+
**returns:** string
24+
2125
### `untildifyUser` (function)
2226

27+
Replaces a tilde with the user's home directory
28+
2329
**Parameters:**
2430

25-
- path (`string`)
31+
- path (`string`) - The path to untildify
2632

27-
**returns:** any
33+
**returns:** string
34+
35+
```tsx
36+
UntildifyUser("~/foo") // /home/user/foo
37+
```
2838

2939
<!-- INSERT GENERATED DOCS END -->
3040

packages/untildify-user/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@
1111
"build": "tsc"
1212
},
1313
"dependencies": {
14-
"admina": "1.0.1",
15-
"untildify": "^5.0.0"
14+
"admina": "1.0.1"
1615
},
1716
"keywords": [
1817
"tilde",

packages/untildify-user/src/index.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,39 @@
11
import { join } from "path"
2-
import untildify from "untildify"
32
import { isSudo } from "admina"
3+
import { homedir } from "os"
44

5-
export function untildifyUser(path: string) {
6-
if (isSudo() && typeof process.env.SUDO_USER === "string") {
5+
export function userHomeDir() {
6+
if (isSudo() && typeof process.env.SUDO_USER === "string" && process.env.SUDO_USER !== "") {
77
// use the user profile even if root
88
if (process.platform === "darwin") {
9-
return join("/Users/", process.env.SUDO_USER, path)
9+
return join("/Users/", process.env.SUDO_USER)
1010
} else {
11-
return join("/home/", process.env.SUDO_USER, path)
11+
return join("/home/", process.env.SUDO_USER)
1212
}
1313
} else {
14-
return untildify(`~/${path}`)
14+
const maybeHomeDir = homedir()
15+
if (maybeHomeDir === "") {
16+
return undefined
17+
}
18+
return maybeHomeDir
19+
}
20+
}
21+
22+
const tildeRegex = /^~(?=$|\/|\\)/
23+
24+
/**
25+
* Replaces a tilde with the user's home directory
26+
*
27+
* @example UntildifyUser("~/foo") // /home/user/foo
28+
*
29+
* @param path The path to untildify
30+
* @returns The untildified path
31+
*/
32+
export function untildifyUser(path: string) {
33+
const maybeHomeDir = userHomeDir()
34+
if (maybeHomeDir === undefined) {
35+
return path
1536
}
37+
38+
return path.replace(tildeRegex, maybeHomeDir)
1639
}

pnpm-lock.yaml

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/kcov/kcov.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ async function getCmake() {
8181
if (cmake === null) {
8282
const { binDir } = await setupCmake(
8383
getVersion("cmake", undefined, await ubuntuVersion()),
84-
join(untildifyUser(""), "cmake"),
84+
join(untildifyUser("~"), "cmake"),
8585
"",
8686
)
8787
cmake = join(binDir, "cmake")
8888
}
8989
const ninja = which.sync("ninja", { nothrow: true })
9090
if (ninja === null) {
91-
await setupNinja(getVersion("ninja", undefined, await ubuntuVersion()), join(untildifyUser(""), "ninja"), "")
91+
await setupNinja(getVersion("ninja", undefined, await ubuntuVersion()), join(untildifyUser("~"), "ninja"), "")
9292
}
9393
return cmake
9494
}

src/main.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ async function main(args: string[]): Promise<number> {
3939
const arch = opts.architecture ?? process.arch
4040

4141
// the installation dir for the tools that are downloaded directly
42-
const setupCppDir = process.env.SETUP_CPP_DIR ?? untildifyUser("")
42+
const setupCppDir = process.env.SETUP_CPP_DIR ?? untildifyUser("~")
4343

4444
// report messages
4545
const successMessages: string[] = []

src/nala/__tests__/nala.test.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@ describe("setup-nala", () => {
1717
afterAll(() => {
1818
// remove nala to run the rest of the tests with apt-get
1919
execRootSync("apt-get", ["remove", "-y", "nala"])
20-
execRootSync("apt-get", ["remove", "-y", "nala-legacy"])
20+
21+
try {
22+
execRootSync("apt-get", ["remove", "-y", "nala-legacy"])
23+
} catch (err) {
24+
// ignore
25+
console.error(err)
26+
}
2127
})
2228
})

src/python/__tests__/python.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ describe("setup-python", () => {
2828

2929
const installInfo = await setupPython(getVersion("python", "true", await ubuntuVersion()), directory, process.arch)
3030

31-
await testBin("python", ["--version"], installInfo.binDir)
31+
const python = process.platform === "darwin" ? "python3" : "python"
32+
await testBin(python, ["--version"], installInfo.binDir)
3233
})
3334

3435
afterAll(async () => {

src/utils/env/addEnv.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export async function addPath(path: string) {
100100
}
101101
}
102102

103-
export const cpprc_path = untildifyUser(".cpprc")
103+
export const cpprc_path = untildifyUser("~/.cpprc")
104104

105105
async function addEnvSystem(name: string, valGiven: string | undefined, options: AddEnvOptions) {
106106
const val = valGiven ?? ""
@@ -188,12 +188,12 @@ export async function setupCppInProfile() {
188188

189189
try {
190190
// source cpprc in .profile
191-
const profile_path = untildifyUser(".profile")
191+
const profile_path = untildifyUser("~/.profile")
192192
appendFileSync(profile_path, source_cpprc_string)
193193
info(`${source_cpprc_string} was added to ${profile_path}`)
194194

195195
// source cpprc in .bashrc too
196-
const bashrc_path = untildifyUser(".bashrc")
196+
const bashrc_path = untildifyUser("~/.bashrc")
197197
appendFileSync(bashrc_path, source_cpprc_string)
198198
info(`${source_cpprc_string} was added to ${bashrc_path}`)
199199
} catch (err) {

src/utils/setup/setupPipPack.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { hasDnf } from "../env/hasDnf"
1515
import { setupDnfPack } from "./setupDnfPack"
1616
import { isUbuntu } from "../env/isUbuntu"
1717
import { setupAptPack } from "./setupAptPack"
18+
import { untildifyUser } from "untildify-user"
19+
import { mkdirp } from "mkdirp"
1820

1921
export type SetupPipPackOptions = {
2022
/** Whether to use pipx instead of pip */
@@ -56,8 +58,17 @@ export async function setupPipPackWithPython(
5658
const upgradeFlag = upgrade ? (isPipx ? ["upgrade"] : ["install", "--upgrade"]) : ["install"]
5759
const userFlag = !isPipx && user ? ["--user"] : []
5860

61+
const env = process.env
62+
63+
if (isPipx && user) {
64+
// install to user home
65+
env.PIPX_HOME = await getPipxHome()
66+
env.PIPX_BIN_DIR = await getPipxBinDir()
67+
}
68+
5969
execaSync(givenPython, ["-m", pip, ...upgradeFlag, ...userFlag, nameAndVersion], {
6070
stdio: "inherit",
71+
env,
6172
})
6273
} catch (err) {
6374
info(`Failed to install ${name} via ${pip}: ${err}.`)
@@ -83,6 +94,53 @@ export async function hasPipx(givenPython: string) {
8394
return (await execa(givenPython, ["-m", "pipx", "--help"], { stdio: "ignore", reject: false })).exitCode === 0
8495
}
8596

97+
async function getPipxHome_raw() {
98+
let pipxHome = process.env.PIPX_HOME
99+
if (pipxHome !== undefined) {
100+
return pipxHome
101+
}
102+
103+
// Based on https://pipx.pypa.io/stable/installation/
104+
const compatHome = untildifyUser("~/.local/pipx")
105+
if (await pathExists(compatHome)) {
106+
return compatHome
107+
}
108+
109+
switch (process.platform) {
110+
case "win32": {
111+
pipxHome = untildifyUser("~/AppData/Local/pipx")
112+
break
113+
}
114+
case "darwin": {
115+
pipxHome = untildifyUser("~/Library/Application Support/pipx")
116+
break
117+
}
118+
default: {
119+
pipxHome = untildifyUser("~/.local/share/pipx")
120+
break
121+
}
122+
}
123+
124+
await mkdirp(pipxHome)
125+
await mkdirp(join(pipxHome, "trash"))
126+
await mkdirp(join(pipxHome, "shared"))
127+
await mkdirp(join(pipxHome, "venv"))
128+
return pipxHome
129+
}
130+
const getPipxHome = memoize(getPipxHome_raw, { isPromise: true })
131+
132+
async function getPipxBinDir_raw() {
133+
if (process.env.PIPX_BIN_DIR !== undefined) {
134+
return process.env.PIPX_BIN_DIR
135+
}
136+
137+
const pipxBinDir = untildifyUser("~/.local/bin")
138+
await addPath(pipxBinDir)
139+
await mkdirp(pipxBinDir)
140+
return pipxBinDir
141+
}
142+
const getPipxBinDir = memoize(getPipxBinDir_raw, { isPromise: true })
143+
86144
async function getPython_raw(): Promise<string> {
87145
const pythonBin = (await setupPython(getVersion("python", undefined, await ubuntuVersion()), "", process.arch)).bin
88146
if (pythonBin === undefined) {

0 commit comments

Comments
 (0)