Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit bb6f560

Browse files
committed
fix: improve listing of envs
1 parent dcdb800 commit bb6f560

File tree

7 files changed

+263
-6
lines changed

7 files changed

+263
-6
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM nix/nixos

README_x.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
2+
3+
### Environments
4+
5+
```yaml
6+
packages:
7+
- R
8+
variables:
9+
- R_SITE_LIB: /library
10+
```
11+
12+
13+
14+
### Create an environment
15+
16+
The `create` command lets you create a new environment
17+
18+
```bash
19+
nixta create <name> [extends <env1,env2,...>] [adds <pkg1,pkg2,...>] [removes <pkg3,pkg4,...>]
20+
```
21+
22+
For example,
23+
24+
```bash
25+
nixta create myenv extends r adds r-ggplot2,r-rfishbase
26+
```
27+
28+
29+
```yaml
30+
extends:
31+
- r
32+
adds:
33+
- r-ggplot2
34+
- r-rfishbase
35+
```
36+
37+
### Delete an environment
38+
39+
```bash
40+
nixta delete <name>
41+
```
42+
43+
For example,
44+
45+
```bash
46+
nixta delete myenv
47+
```
48+
49+

UTH.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Under the hood
2+
3+
This document provides an "under the hood" look into the workings of Nixster. It's intendended for contributors and interested users.
4+
5+
## Nix
6+
7+
8+
9+
### Normalising package names
10+
11+
One of the things that Nixster needs is a mapping between package names and Nix attribute paths. This allows Nixster to add or remove Nix packages from environments based on their `environ.yaml` file. Sometimes there is consistency between names and attribute paths. For example, the package known on CRAN as `babynames`, has the Nix name `r-babynames-0.3.0` and the attribute name `rPackages.babynames`. Other times there is less consistentcy. For example, the package known on PyPi as `buildbot-grid-view` has the name `python3.7-buildbot-grid-view-1.4.0` and attribute path `python37Packages.buildbot-plugins.grid-view`.
12+
13+
Nixster creates two new columns `name` and `version` by parsing the Nix package name an normalizing it to only contain lowercase letters (`a-z`), digits (`0-9`) and dashes (`-`). To do this, the `nix_name` is parsed
14+
15+
`python-buildbot-grid-view` will install the package with Nix attributue path `python37Packages.buildbot-plugins.grid-view`
16+
17+
18+
```bash
19+
nix-env --query --file "<nixpkgs>" --attr python37Packages --available --attr-path --drv-path --out-path
20+
```
21+
22+
Which produces a list of
23+
24+
```bash
25+
python37Packages.behave behave-1.2.6 /nix/store/y758394y7f23ba30m0n1h52w6hakjg5k-behave-1.2.6.drv /nix/store/8jz1c7bwrl8kch6xag7j93lwg0rf4j77-behave-1.2.6
26+
python37Packages.boost boost-1.67_0 /nix/store/6w3r1wq9snvhx1yvyh4waw8avyjdxffa-boost-1.67_0.drv dev=/nix/store/9p5pj3v6mrwhhjj8ynjw6qb5avn354pj-boost-1.67_0-dev;/nix/store/p7ldzl2pbfa6l5pab3n1iq223q53jf4x-boost-1.67_0
27+
python37Packages.bugseverywhere bugseverywhere-1.1.1 /nix/store/wg2l5y71pgjb2925f0rzp7868cc7xc8r-bugseverywhere-1.1.1.drv /nix/store/i2bln8h615b94wlddjwqmgy1wxblnf3m-bugseverywhere-1.1.1
28+
python37Packages.caffe caffe-1.0 /nix/store/0x7n1xyrjxlijl9557fpzfk5zc1j6d8y-caffe-1.0.drv bin=/nix/store/rj09zb3sxy6n2v9wv3dkg929cjmjymwh-caffe-1.0-bin;/nix/store/n5wxs3hqv5vfgc7858x77x5mk3bqsa4b-caffe-1.0
29+
```
30+
31+
```bash
32+
nix-env --query --file "<nixpkgs>" --attr python37Packages --available --meta --json | head -n 30
33+
```
34+
35+
```bash
36+
{
37+
"python37Packages.behave": {
38+
"name": "behave-1.2.6",
39+
"system": "x86_64-linux",
40+
"meta": {
41+
"available": true,
42+
"description": "behaviour-driven development, Python style",
43+
"homepage": "https://github.com/behave/behave",
44+
"isBuildPythonPackage": [
45+
{
46+
"kernel": {
47+
"_type": "kernel",
48+
"execFormat": {
49+
"_type": "exec-format",
50+
"name": "elf"
51+
},
52+
"families": {},
53+
"name": "linux"
54+
}
55+
},
56+
{
57+
"kernel": {
58+
"families": {
59+
"darwin": {
60+
"_type": "exec-format",
61+
"name": "darwin"
62+
}
63+
}
64+
}
65+
}
66+
```

demo.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env bash
2+
3+
# Script for creating CLI demo
4+
5+
# Include the demoing code
6+
. demo-magic.sh
7+
clear
8+
9+
# Set some options
10+
DEMO_PROMPT=$BLUE"$ "
11+
DEMO_CMD_COLOR=$GREEN
12+
13+
# Alias to cuurent version of CLI in this repo
14+
alias nixster="npx ts-node src/cli.ts"
15+
16+
# Run the demo!
17+
18+
p "# First we'll change into one of the R example projects"
19+
pe "cd tests/fixtures/r-spatial"
20+
21+
p "# And take a look at the files in it"
22+
pe "ls"
23+
sleep 1
24+
25+
p "# The 'main.R' file is what Dockter will execute within a container"
26+
p "# It reads in some spatial data and plots it"
27+
pe "cat main.R"
28+
sleep 1
29+

src/cli.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
#!/usr/bin/env node
2+
13
/**
24
* Module for command line interface (CLI)
35
*
@@ -47,10 +49,27 @@ yargs
4749
}, async (argv: any) => {
4850
const envs = await Environment.envs()
4951
output(envs, argv, (envs: any) => {
50-
return envs.map((env: any) => {
51-
const descr = env.description ? env.description : ''
52-
return sprintf('%-40s %-20s %s', chalk.blue.bold(env.name), descr, chalk.gray(env.location))
53-
}).join('\n')
52+
const layout = '%-15s %-40s %-80s'
53+
const header = sprintf(layout, chalk.gray('Ready'), chalk.gray('Name'), chalk.gray('Description')) + '\n'
54+
return header +
55+
envs.map((env: any) => {
56+
const icon = env.built ? chalk.green('✓') : chalk.yellow('⚪')
57+
const name = chalk.blue(env.name)
58+
let descr = env.description
59+
if (!descr) {
60+
if (env.extends && env.extends.length) {
61+
descr = `Extends ${env.extends.join(', ')}.`
62+
}
63+
if (env.adds && env.adds.length) {
64+
descr = `Adds ${env.adds.length} packages.`
65+
}
66+
if (env.removes && env.removes.length) {
67+
descr = `Removes ${env.removes.length} packages.`
68+
}
69+
}
70+
descr = ellipsize(descr, 80)
71+
return sprintf(layout, icon, name, descr)
72+
}).join('\n')
5473
})
5574
})
5675

src/nix.ts

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Nixster's interface to Nix.
33
*/
4-
4+
import fs from 'fs'
55
import path from 'path'
66

77
import Database from 'better-sqlite3'
@@ -261,13 +261,24 @@ export async function search (term: string, type: string = '', limit: number = 1
261261
return stmt.all(limit)
262262
}
263263

264+
/**
265+
* Has the environment been built yet?
266+
*
267+
* @param env The environment name
268+
*/
269+
export async function built (env: string): Promise<boolean> {
270+
return (await location(env)).length > 0
271+
}
272+
264273
/**
265274
* Get the location of an environment within the Nix store
266275
*
267276
* @param env The environment name
268277
*/
269278
export async function location (env: string): Promise<string> {
270-
const readlink = await spawn('readlink', ['-f', path.join(profiles, env)])
279+
const profile = path.join(profiles, env)
280+
if (!fs.existsSync(profile)) return ''
281+
const readlink = await spawn('readlink', ['-f', profile])
271282
return readlink.toString().trim()
272283
}
273284

src/store.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
const Dat = require('dat-node')
2+
const pda = require('pauls-dat-api')
3+
4+
const DIR = '/home/nokome/nixster'
5+
const KEY = '14f58766270b33ebd18377955c82992214956438e15d22dfb1d0844fa888d8ea'
6+
7+
function share () {
8+
Dat(DIR, {}, (err, dat) => {
9+
if (err) throw err
10+
11+
const importer = dat.importFiles({
12+
count: true,
13+
ignoreDirs: false,
14+
watch: true
15+
})
16+
importer.on('put', (src, dest) => {
17+
console.log(`Importing ${src.name} to ${dest.name}`)
18+
})
19+
importer.on('count', ({files, bytes}) => {
20+
console.log(`Importing ${files} files of ${bytes} bytes`)
21+
})
22+
23+
dat.join()
24+
25+
dat.network.on('connection', () => {
26+
console.log('Connection')
27+
})
28+
29+
const key = dat.key.toString('hex')
30+
console.log(`Sharing store at dat://${key}`)
31+
})
32+
}
33+
34+
function files (path, cb) {
35+
connect(async dat => {
36+
const files = await pda.readdir(dat.archive, path, { recursive: true })
37+
38+
console.log('Leaving network')
39+
dat.leave()
40+
41+
cb(files)
42+
})
43+
}
44+
45+
function sync () {
46+
fetch([
47+
'/db.sqlite3',
48+
'/envs/'
49+
])
50+
}
51+
52+
function fetch (files) {
53+
connect(async dat => {
54+
for (let file of files) {
55+
await pda.download(dat.archive, file)
56+
console.log(`Downloaded ${file}`)
57+
}
58+
dat.leave()
59+
})
60+
}
61+
62+
function connect (cb) {
63+
Dat(DIR + '-client', {key: KEY, sparse: true}, (err, dat) => {
64+
if (err) throw err
65+
66+
console.log('Joining network')
67+
dat.join(function (err) {
68+
if (err) throw err
69+
70+
if (!dat.network.connected || !dat.network.connecting) {
71+
console.error('No users currently online for that key.')
72+
process.exit(1)
73+
}
74+
})
75+
76+
cb(dat)
77+
})
78+
}
79+
80+
module.exports = {
81+
share, fetch, sync, files
82+
}

0 commit comments

Comments
 (0)