Compare commits

...

383 Commits
0.10 ... state

Author SHA1 Message Date
Wouter den Breejen
6af66436f9 2008-03-04 14:16:16 +00:00
Wouter den Breejen
b6659d4425 Script to automatically checkout and create a snix release. 2008-03-04 13:30:53 +00:00
Wouter den Breejen
ab649814fc Merged trunk R.10943 back in 2008-03-04 12:15:55 +00:00
Wouter den Breejen
bffb03eae1 makeValidityRegistration only supports store paths for now .... 2008-02-07 00:06:04 +00:00
Wouter den Breejen
2bf4fcb7cd Merged trunk back in: 10154->10531. 2008-02-06 23:58:00 +00:00
Wouter den Breejen
a34a198006 Merged the Nix sources from the trunk from R9751 to R10133 for my State Nix project. 2008-01-13 16:36:27 +00:00
Wouter den Breejen
55b07d65b1 Merged trunk R9751 back in. 2007-11-19 11:47:41 +00:00
Wouter den Breejen
4e11da960c 2007-11-09 09:50:17 +00:00
Wouter den Breejen
1164d6a389 Merged to R9561; Fixed initial snapshot bug. 2007-10-31 15:08:22 +00:00
Wouter den Breejen
c28742f633 Now using ln -snf to ensure symlinks are overwritten; Fixed --showstatepaths 2007-10-26 10:02:58 +00:00
Wouter den Breejen
7e0dcc5dcb Runtime state arguments added to nix-state. 2007-10-23 14:02:25 +00:00
Wouter den Breejen
c0dceea9f0 2007-10-22 13:22:56 +00:00
Wouter den Breejen
588356c30a Replaced calls to drvFromPath with database calls. 2007-10-19 16:43:37 +00:00
Wouter den Breejen
1747d649c5 2007-10-19 13:42:17 +00:00
Wouter den Breejen
53e31381fa State dirs/files to be versioned and state rights (user,grp,chmod) are now store in the db. Thuss we can remove their derivations at garbage collection time. 2007-10-18 17:45:31 +00:00
Wouter den Breejen
2d84c9e50c Garbage Collection for state paths now works. (altough we don't set locks on state paths or handle cyclic references) 2007-10-18 13:33:50 +00:00
Wouter den Breejen
a699c6b330 fix for queryStoreReferences 2007-10-18 12:08:53 +00:00
Wouter den Breejen
84d00db70b Used Rsync for reverting state. 2007-10-17 11:16:57 +00:00
Wouter den Breejen
138973a6d5 setSnapshot & build-stateinfo fixes 2007-10-16 17:11:18 +00:00
Wouter den Breejen
d8e9dc2775 Garbage collection - gcKeepDerivations bug 2007-10-15 19:17:30 +00:00
Wouter den Breejen
ef37776094 Added more state garbage collection code 2007-10-12 17:18:39 +00:00
Wouter den Breejen
60a32fcbf3 Fixed recursive build error 2007-10-12 14:01:43 +00:00
Wouter den Breejen
0ee803935e Recursive build error.... *2 2007-10-12 10:05:17 +00:00
Wouter den Breejen
65ba1f3008 Recursive build error.... 2007-10-12 10:04:58 +00:00
Wouter den Breejen
16410fc714 Merged to R9439. Fixed a computeFSClosure bug. The state garbage colletor basically works, Missing items: State locks, shared state and Topological sort 2007-10-10 15:55:00 +00:00
Wouter den Breejen
7d82fd16e9 Merged R9433 2007-10-09 21:12:02 +00:00
Wouter den Breejen
8b31968c61 Merged to R9429 2007-10-08 14:53:37 +00:00
Wouter den Breejen
67022b7cca Merged latest trunk revision R9332 into my state branch :) 2007-10-08 14:09:02 +00:00
Wouter den Breejen
a94ea0fd61 Merged R9217 2007-10-08 14:04:55 +00:00
Wouter den Breejen
ca3d96222a Merged R9207 2007-10-08 12:47:47 +00:00
Wouter den Breejen
13b632ca57 Fixes to decodeValidPathInfo and cleanups 2007-10-08 12:24:02 +00:00
Wouter den Breejen
dacf2e0e87 Merged R9105 2007-10-08 11:58:34 +00:00
Wouter den Breejen
00602dd20c Merged R9063 2007-10-08 10:41:41 +00:00
Wouter den Breejen
546ca6e8bc Merged R8864 2007-10-08 10:26:21 +00:00
Wouter den Breejen
854e155b2c Merged R8636 2007-10-08 10:20:43 +00:00
Wouter den Breejen
8e9c7d9338 Merged R8632 2007-10-08 10:15:18 +00:00
Wouter den Breejen
3800f55b54 Merging the trunk back into my branch: just merged revision 8628 2007-10-07 14:32:42 +00:00
Wouter den Breejen
d69dd855d5 Added some state-specific garbage collection code (not complete yet) 2007-10-05 19:33:27 +00:00
Wouter den Breejen
43d93e5e64 Replaced cp for rsync to copy state 2007-10-03 09:46:22 +00:00
Wouter den Breejen
d0458acb7c Implemented runtime --share= and --unshare options. Fixed some things. 2007-10-02 15:52:50 +00:00
Wouter den Breejen
86f0fd8341 Fixed ~ and * to expand in cp and ln commands. 2007-09-19 22:00:43 +00:00
Wouter den Breejen
4c32f38047 2007-09-19 14:26:16 +00:00
Wouter den Breejen
f435abcdb6 Fixed recalculated drv path issue. 2007-09-18 17:01:17 +00:00
Wouter den Breejen
51cff21c92 Fixed sharing issue. Created unshare method. 2007-09-18 15:10:48 +00:00
Wouter den Breejen
315cd18337 2007-09-17 15:38:13 +00:00
Wouter den Breejen
e80c7bda4c 2007-09-11 16:22:07 +00:00
Wouter den Breejen
ed55982085 Fixed remote issues 2007-09-05 14:13:50 +00:00
Wouter den Breejen
35e239af33 EOF 2007-09-04 17:09:26 +00:00
Wouter den Breejen
89ab441fd2 Changed the [solid-state-dependencies] list in the derivation to a single variable 'externalState' (since we also have a single state path) which can, for instance, be set to ~/.mozilla-test in the case of firefox (not bugfree yet) 2007-09-03 19:22:09 +00:00
Wouter den Breejen
68cb244c90 Fixed bugs in revertToRevision and getSharedWithPathSetRecTxn. Users can now also revert to older revisions. 2007-09-03 12:13:22 +00:00
Wouter den Breejen
094c69ad19 2007-08-31 15:19:55 +00:00
Wouter den Breejen
ec7b0afb08 Fixed showrevisions. added commit/run/scan only options 2007-08-30 18:51:19 +00:00
Wouter den Breejen
30cf65af26 Fixed some more remote-store store bugs. Users can now add state store components with nix-env. Paths in /nix/state are now chowned and chmodded to their owners 2007-08-30 18:20:20 +00:00
Wouter den Breejen
627afcc1aa Fixed a lot of remote store issues. But there is still a bug with 32bit unsigned integers: 'implementation cannot deal with > 32-bit integers' 2007-08-28 15:22:27 +00:00
Wouter den Breejen
2e7539bd27 Added state marshall functions in RemoteStore.cc (still unfinished in Nix-worker.cc) 2007-08-27 18:54:05 +00:00
Wouter den Breejen
bdcce95a39 Added / Removed state functions to the Store API 2007-08-27 13:09:24 +00:00
Wouter den Breejen
53a6b9aaa5 * Fixed very old transactional bug that caused a freeze sometimes
* State components that get their state at runtime can now be (un)installed with nix-env
2007-08-17 15:35:34 +00:00
Wouter den Breejen
05297240ea fixed some hard links 2007-08-16 13:44:53 +00:00
Wouter den Breejen
53c907ca09 Fixed ugly '--hello' exception in builder.pl 2007-08-14 17:54:05 +00:00
Wouter den Breejen
5a9cfdeb6e bugfixes 2007-08-14 17:34:45 +00:00
Wouter den Breejen
4089bd5f19 State is now maintained (their paths are automatically shared), unless sharedState is set in the nix-expr, when a new version with the same drv-name of the component is installed 2007-08-13 15:35:12 +00:00
Wouter den Breejen
7424d72098 Partially integrated state components (startscripts) into nix-env 2007-08-10 15:39:02 +00:00
Wouter den Breejen
13f321e397 State revisions are now printed like this: Rev. 01 @ Mon Aug 6 15:48:37 2007 (1186408117) -- Initial build revision. 2007-08-06 15:01:39 +00:00
Wouter den Breejen
696f1fd5e2 before allowing comments to revisions 2007-08-06 12:13:53 +00:00
Wouter den Breejen
af8c5697be Cleaned up code, fixed some TODO's 2007-08-03 16:25:59 +00:00
Wouter den Breejen
bd25de8d88 Fixed referrer issue 2007-08-03 14:50:05 +00:00
Wouter den Breejen
5e0716bbbb Fixed referrer issue 2007-08-03 14:46:53 +00:00
Wouter den Breejen
7d91f62b71 before removing referrer code 2007-08-03 10:30:39 +00:00
Wouter den Breejen
4fb9070fbd before removing referrer code 2007-08-03 10:28:58 +00:00
Wouter den Breejen
83ec65edf5 2007-07-27 16:22:53 +00:00
Wouter den Breejen
856251df03 Fixed revert issue 2007-07-26 11:39:55 +00:00
Wouter den Breejen
0fc5accd86 Replaced SVN by Ext3COW as a backend for state (still some things need to happen: reverting doesn't go right in all cases yet) 2007-07-25 21:52:33 +00:00
Wouter den Breejen
dc4395b737 2007-07-24 12:47:28 +00:00
Wouter den Breejen
a07ba681cc 2007-07-23 15:03:36 +00:00
Wouter den Breejen
45bb1ae6a5 Added ext3cow lib 2007-07-23 14:38:23 +00:00
Wouter den Breejen
e3034da88b 2007-07-23 14:36:36 +00:00
Wouter den Breejen
00f39f88f7 adjusted queryReferences/Referrers to handle shared state paths. 2007-07-20 11:03:30 +00:00
Wouter den Breejen
7f2140d17f Before adjusting queryReferences/Referrers to handle shared state paths 2007-07-19 12:25:38 +00:00
Wouter den Breejen
b46db4dea7 2007-07-18 11:19:41 +00:00
Wouter den Breejen
c0bd494865 Firefox can now be brought under state control, however, the symlink ~/.mozilla/firefox/ --> /nix/state/...../ can not (yet) be created automatically at build time since ~/ is set to /homeless-shelter/ ... 2007-07-13 18:37:25 +00:00
Wouter den Breejen
b6974f2ae6 before adding solid-state dependencies to be able to support state for components that can't be configured to store state in /nix/state/.../ (like firefox) 2007-07-13 13:02:43 +00:00
Wouter den Breejen
6392da5f90 Files and directorys are now properly 'svn deleted' 2007-07-13 11:48:57 +00:00
Wouter den Breejen
e33a1e4e74 coputeFSClosure is now transactional, state will now be commited after the component has been build 2007-07-12 15:59:16 +00:00
Wouter den Breejen
f3dabd6206 before making computeFSClosure recursively transactional ..... (adding Transaction txn) 2007-07-12 14:46:15 +00:00
Wouter den Breejen
7bfed0c104 2007-07-12 11:34:17 +00:00
Wouter den Breejen
96a62bb7e6 2007-07-12 10:51:10 +00:00
Wouter den Breejen
36b79c7135 before moving some functions to nix-state 2007-07-11 13:40:29 +00:00
Wouter den Breejen
ba437f451e 2007-07-10 09:23:42 +00:00
Wouter den Breejen
b378df6484 2007-07-09 21:30:11 +00:00
Wouter den Breejen
fdc2686460 Rectification: isStateComponentTxn should not be removed, the error was caused by a bug in scanAndUpdateAllReferencesTxn 2007-07-09 14:57:45 +00:00
Wouter den Breejen
b7654ab716 before removing isStateComponentTxn 2007-07-09 14:30:57 +00:00
Wouter den Breejen
9257f16c85 Besides directorys, single files can now also be versioned (or excluded) 2007-07-09 11:59:29 +00:00
Wouter den Breejen
bc2fbabc12 Fixed bugs, cleaned up some code 2007-07-09 00:28:38 +00:00
Wouter den Breejen
afb445957d States can now be (recursively) rolled back and forward :) 2007-07-08 22:59:44 +00:00
Wouter den Breejen
9f00b42f38 downscaled to 1 repos per statePath 2007-07-08 22:40:16 +00:00
Wouter den Breejen
cce4156232 before downscaling to 1 repos per statePath 2007-07-08 19:58:16 +00:00
Wouter den Breejen
ca5fc7c582 major update 2007-07-08 19:02:08 +00:00
Wouter den Breejen
cc7d4c8bd7 2007-07-06 19:15:05 +00:00
Wouter den Breejen
40161d0be1 runProgram backup2 2007-07-06 15:20:46 +00:00
Wouter den Breejen
0a4a3a1b68 runProgram backup2 2007-07-06 15:18:37 +00:00
Wouter den Breejen
4f483aad0f runProgram backup 2007-07-06 15:12:20 +00:00
Wouter den Breejen
eb1f179eac separated references and referrers both into 4 tables: links from: component or state to: state or component 2007-07-04 18:53:13 +00:00
Wouter den Breejen
9d7438db9f Before seperation of dbs references_state and references (and referrers) 2007-07-04 12:32:19 +00:00
Wouter den Breejen
c65c296ce0 Before trying to install STLdb4 .... 2007-07-03 13:50:16 +00:00
Wouter den Breejen
ad2b815b5e added scanAndUpdateAllReferencesTxn(..) moving on to create a db-table that can save state-revision-closures and state-revision-reference-closures 2007-07-02 19:15:10 +00:00
Wouter den Breejen
1c3ec86c39 Fixed bug in build.cc All paths are now correctly scanned for the statpaths from the derivation inputs 2007-06-29 20:45:37 +00:00
Wouter den Breejen
c370c9f535 adjusted to: void computeFSClosure(const Path & path, PathSet & paths, const bool & withComponents, const bool & withState, bool flipDirection) 2007-06-29 15:24:51 +00:00
Wouter den Breejen
7eb2f61797 Before adjusting computeFSClosure 2007-06-29 14:56:32 +00:00
Wouter den Breejen
b32691da2b registerValidPath can now also take state paths as arguments, nix-store still cannot 2007-06-28 18:59:07 +00:00
Wouter den Breejen
04dd3fdf34 Bugfix: Before adjusting registerValidPath to also be able to take state paths 2007-06-28 17:12:02 +00:00
Wouter den Breejen
22473597ec merged executeAndPrintShellCommand to runProgram 2007-06-28 13:20:45 +00:00
Wouter den Breejen
b9fe3f00c1 merged executeAndPrintShellCommand to runProgram 2007-06-28 13:17:03 +00:00
Wouter den Breejen
729933062b before merging executeAndPrintShellCommand to runProgram 2007-06-28 11:11:09 +00:00
Wouter den Breejen
1c0b052243 before merging executeAndPrintShellCommand to runProgram 2007-06-28 11:05:11 +00:00
Wouter den Breejen
3d22bd50b3 nix-state now works, state is recursively commited (when necessary) 2007-06-27 15:43:16 +00:00
Wouter den Breejen
c0dcfed3c3 New state queries for nix-store now work:
--requisites / -R: print all paths necessary to realise a path
--requisites-withstate: same as --requisites but now also including state paths
--references: print all paths referenced by the given path
--references-state: print all state paths referenced by the given path  
--referrers: print all paths directly refering to the given path
--referrers-state: print all state paths directly refering to the given path
--referrers-closure: print all paths (in)directly refering to the given path
--referrers-closure-withstate: same as --referrers-closure but now also including state paths
2007-06-22 14:59:03 +00:00
Wouter den Breejen
6351b7e728 added dbValidStatePaths, StatePaths are now also registered as valid and can be query'd on validity 2007-06-22 14:04:06 +00:00
Wouter den Breejen
51fad07fbd Before adding dbValidStatePaths 2007-06-22 13:03:06 +00:00
Wouter den Breejen
0e41b191bf 2007-06-21 16:47:48 +00:00
Wouter den Breejen
a4fda31ad5 Before editting get-drvs.hh: DrvInfo 2007-06-21 13:26:58 +00:00
Wouter den Breejen
235c91dd7f State paths can now be scanned and queryed (references), referres still need to be added 2007-06-19 15:23:00 +00:00
Wouter den Breejen
5164a77aab Before moving scanForStateReferences(...) 2007-06-19 13:05:45 +00:00
Wouter den Breejen
b1cc9e9a45 Before moving scanForStateReferences(...) 2007-06-19 13:04:05 +00:00
Wouter den Breejen
bdecf3bdbc In the middle of adding state references to derivations and the db... 2007-06-18 19:54:31 +00:00
Wouter den Breejen
5e59387d40 Before giving all store-state-runtime-paths a unique hash storepath 2007-06-14 14:16:53 +00:00
Wouter den Breejen
df43c1e5b9 Before adjusting getStateReferencesClosure_ 2007-06-13 16:18:42 +00:00
Wouter den Breejen
184443d18d Before adjusting getStateReferencesClosure_ 2007-06-13 15:18:57 +00:00
Wouter den Breejen
bc0af4449a dont commit binarys... 2007-06-12 21:03:56 +00:00
Wouter den Breejen
76f5c8ba07 Almost finished the identifier/user/multiple-derivations mod 2007-06-12 21:01:55 +00:00
Wouter den Breejen
b909d57f5d broken, in the middle of edditting user / drv mod 2007-06-12 19:08:05 +00:00
Wouter den Breejen
fe04276aef before adjusting derivers table 2007-06-12 12:48:35 +00:00
Wouter den Breejen
95ce7e04b7 Nix now includes the username into the hash calculation, statepaths are also recomputed at buildtime so they cannot be spoofed 2007-06-11 16:43:32 +00:00
Wouter den Breejen
267ccc589d Nix now understands the difference between runtime-state-components and non-runtime-state-compontens. Components and Derivations are now properly (re)build/derived (or not) when necessary. 2007-06-08 16:00:55 +00:00
Wouter den Breejen
fd2b8271e4 Fixed a bug in the auto-deleted-checkout part of the commit bash script, Had to use a hack to get bash to support 2D arrays.... 2007-06-07 18:59:20 +00:00
Wouter den Breejen
255bf5f04b Fixed a bug in the auto-deleted-checkout part of the commit bash script, Had to use a hack to get bash to support 2D arrays.... 2007-06-07 18:39:22 +00:00
Wouter den Breejen
01062b0563 Removed collision-bug between repositorys, each group of repositorys and each individual repository has now a scannable unique hash 2007-06-07 14:08:57 +00:00
Wouter den Breejen
79d5604780 Changed commit script: it recursively walkes through all dirs itself now, uses svn stat where needed, and doesnt use svn add *,svn revert anymore and is much faster 2007-06-07 13:16:38 +00:00
Wouter den Breejen
7166ad8eba Completed updateStateDerivation(Path storepath) method 2007-06-04 19:41:46 +00:00
Wouter den Breejen
bcf9d3ab2f 2007-06-04 16:51:15 +00:00
Wouter den Breejen
9c46444641 Before creating multiple derivation - component instances 2007-05-31 17:18:13 +00:00
Wouter den Breejen
986a50ac78 cleanup old shell script 2007-05-30 17:17:04 +00:00
Wouter den Breejen
25117fd165 the command /nixstate/nix/bin/nix-state --run /nix/store/sig2qgvaayydrwy5hn6b2dm5r2ayhv5s-hellohardcodedstateworld-1.0 now causes state to be checked and comitted 2007-05-30 17:16:25 +00:00
Wouter den Breejen
653e557e81 Before modifying commit shell script 2007-05-30 11:27:01 +00:00
Wouter den Breejen
cbd0d39583 Added beginnnings of getStatePathClosure and GetDrv in local-store.cc, next: setting up variables in nix-state to recursively commit state 2007-05-29 15:42:44 +00:00
Wouter den Breejen
fbd1b78a9d Finished set-up for nix-state, now: adding runtime state parameters & exclude state-identifier as input from state-hash 2007-05-29 11:34:54 +00:00
Wouter den Breejen
0a303ea2c0 before changing db schema 2007-05-25 12:27:36 +00:00
Wouter den Breejen
c9e78a973a Created commit shell script; next adding nix-state 2007-05-24 15:08:12 +00:00
Wouter den Breejen
97eb8c32a0 created sub commit scripts 2007-05-22 16:57:36 +00:00
Wouter den Breejen
86b053dd80 Fixed backwards compatible hack & added state creation call after build 2007-05-22 13:19:27 +00:00
Wouter den Breejen
73995157e3 nixstate is now backwards comptible (because of some ugly hack ..) 2007-05-22 12:14:16 +00:00
Wouter den Breejen
09b8b7efbc Added backwards compatib. but still something... remains that changes the hashes .... :( 2007-05-21 23:42:20 +00:00
Wouter den Breejen
802d7f40bd Small fix 2007-05-21 21:56:34 +00:00
Wouter den Breejen
5cac336820 Repositorys are created, state dirs are checked out automatically 2007-05-21 21:34:49 +00:00
Wouter den Breejen
3fc0b0da58 build error 2007-05-20 12:29:55 +00:00
Wouter den Breejen
8a7874d77d in the middle of adding nixStoreState ... 2007-05-18 19:50:58 +00:00
Wouter den Breejen
4c63f18dcc added state options and state locations into drv 2007-05-16 10:16:10 +00:00
Wouter den Breejen
b712f0f019 First commit 2007-05-15 09:26:33 +00:00
Eelco Dolstra
1a793c60ce * Branch for state support in Nix. 2007-04-05 11:45:20 +00:00
Eelco Dolstra
ae7990cc88 * Work around a bug in Apple's GCC preprocessor. 2007-03-30 13:24:35 +00:00
Eelco Dolstra
4caca58ff7 * Make the maximum patch size configurable. 2007-03-30 09:01:05 +00:00
Eelco Dolstra
17b506c0c7 * Handle ECONNRESET from the client. Also, don't abort() if there are
unexpected conditions in the SIGPOLL handler, since that messes up
  the Berkeley DB environment (which a client must never be able to
  trigger).
2007-03-28 15:46:21 +00:00
Eelco Dolstra
efd31139df * Forgot a @bindir@. 2007-03-27 09:53:58 +00:00
Eelco Dolstra
d303b389a9 * `nix-copy-closure --from': copy from a remote machine instead of to
a remote machine.
2007-03-26 21:05:17 +00:00
Eelco Dolstra
7edd2e2cd2 * Refactoring. 2007-03-26 20:49:22 +00:00
Eelco Dolstra
f3584ff535 * Fix URL/description. 2007-03-21 12:39:55 +00:00
Eelco Dolstra
803cb6e3b9 * Override the setuid helper using NIX_SETUID_HELPER. 2007-03-20 22:04:25 +00:00
Eelco Dolstra
a8ea4cbcc8 * Scan /proc/sys/kernel/modprobe for roots to prevent the kernel
modules for the running kernel from being garbage-collected.  Idem
  for /proc/sys/kernel/fbsplash.
2007-03-20 11:13:15 +00:00
Eelco Dolstra
8ab229ddf2 * Terminate build hooks and substitutes with a TERM signal, not a KILL
signal.  This is necessary because those processes may have joined
  the BDB environment, so they have to be given a chance to clean up.
  (NIX-85)
2007-03-19 12:48:45 +00:00
Eelco Dolstra
b2b6cf3fc8 * Undocumented option `gc-check-reachability' to allow reachability
checking to be turned off on machines with way too many roots.
2007-03-19 09:16:47 +00:00
Eelco Dolstra
eb2dd4815c * Remove old generations in all directories under
/nix/var/nix/profiles, not just in that directory itself.  (NixOS
  puts profiles in /nix/var/nix/profiles/per-user.)
2007-03-13 11:30:57 +00:00
Eelco Dolstra
917e06bf63 * Delete the output paths before invoking the build hook. 2007-03-07 15:53:11 +00:00
Eelco Dolstra
df0283ae86 * Get rid of those stupid --login tricks, it's the responsibility of
the remote system to make sure that Nix is in the $PATH.
2007-03-01 13:55:47 +00:00
Eelco Dolstra
30394a4f3f * sh -> bash. 2007-03-01 13:49:20 +00:00
Eelco Dolstra
db1973d012 * Look for the openssl program at compile time. If not found, call
openssl through $PATH at runtime.
2007-03-01 13:30:46 +00:00
Eelco Dolstra
b4a040e52b * Don't check the signature unless we have to. 2007-03-01 12:30:24 +00:00
Eelco Dolstra
2ea3bebc23 * Doh! The deriver can be empty. 2007-02-27 23:18:57 +00:00
Eelco Dolstra
044b6482c1 * Greatly reduced the amount of stack space used by the Nix expression
evaluator.  This was important because the NixOS expressions started
  to hit 2 MB default stack size on Linux.

  GCC is really dumb about stack space: it just adds up all the local
  variables and temporaries of every scope into one huge stack frame.
  This is really bad for deeply recursive functions.  For instance,
  every `throw Error(format("error message"))' causes a format object
  of a few hundred bytes to be allocated on the stack.  As a result,
  every recursive call to evalExpr2() consumed 4680 bytes.  By
  splitting evalExpr2() and by moving the exception-throwing code out
  of the main functions, evalExpr2() now only consumes 40 bytes.
  Similar for evalExpr().
2007-02-27 19:10:45 +00:00
Eelco Dolstra
adce01a8d0 * When NIX_SHOW_STATS=1, show the amount of stack space consumed by
the Nix expression evaluator.
2007-02-27 17:28:51 +00:00
Eelco Dolstra
363e307fd3 * Error message to stdout. 2007-02-26 23:32:10 +00:00
Eelco Dolstra
ddde8e2f32 * Handle EINTR in select(). 2007-02-22 18:15:29 +00:00
Eelco Dolstra
27bb0ac7d2 * /man -> /share/man 2007-02-22 17:00:58 +00:00
Eelco Dolstra
fa2be32034 * nix-copy-closure: force a login shell on the remote machine to make
sure that nix-store is in the PATH.
* nix-copy-closure: option --gzip to compress data.
2007-02-22 16:42:01 +00:00
Eelco Dolstra
4c5e6d1a2f * nix-copy-closure: option --sign.
* nix-copy-closure: set SSH options through NIX_SSHOPTS..
2007-02-22 15:48:20 +00:00
Eelco Dolstra
024a8ed382 * New command `nix-copy-closure' to copy a closure to a Nix store on
another machine through ssh.  E.g.,

    $ nix-copy-closure xyzzy $(which svn)

  copies the closure of Subversion to machine `xyzzy'.  This is like
  `nix-pack-closure $(which svn) | ssh xyzzy', but it's much more
  efficient since it only copies those paths that are missing on the
  target machine.
2007-02-21 23:14:53 +00:00
Eelco Dolstra
7f6161ab3a * Flush cout to show progress. 2007-02-21 23:08:55 +00:00
Eelco Dolstra
0db450024d * Export/import many paths in one go. 2007-02-21 23:00:31 +00:00
Eelco Dolstra
9da367b7d5 * `nix-store -qR' and friends: print the paths sorted topologically
under the references relation.  This is useful for commands that
  want to copy paths to another Nix store in the right order.
2007-02-21 22:45:10 +00:00
Eelco Dolstra
881feb9698 * Flag --print-invalid' in nix-store --check-validity' to print out
which paths specified on the command line are invalid (i.e., don't
  barf when encountering an invalid path, just print it).  This is
  useful for build-remote.pl to figure out which paths need to be
  copied to a remote machine.  (Currently we use rsync, but that's
  rather inefficient.)
2007-02-21 17:57:59 +00:00
Eelco Dolstra
65f195f4c7 * Check that the file containing the secret key is secret. 2007-02-21 17:51:10 +00:00
Eelco Dolstra
bdadb98de8 * `nix-store --import' now also works in remote mode. The worker
always requires a signature on the archive.  This is to ensure that
  unprivileged users cannot add Trojan horses to the Nix store.
2007-02-21 17:34:02 +00:00
Eelco Dolstra
0f5da8a83c * Support exportPath() in remote mode. 2007-02-21 16:34:00 +00:00
Eelco Dolstra
dc7d594776 * importPath(): set the deriver.
* exportPath(): lock the path, use a transaction.
2007-02-21 16:23:25 +00:00
Eelco Dolstra
43c4d18c6a * nix-store --import': import an archive created by nix-store
--export' into the Nix store, and optionally check the cryptographic
  signatures against /nix/etc/nix/signing-key.pub.  (TODO: verify
  against a set of public keys.)
2007-02-21 15:45:32 +00:00
Eelco Dolstra
46e0919ced * `nix-store --export --sign': sign the Nix archive using the RSA key
in /nix/etc/nix/signing-key.sec
2007-02-21 14:31:42 +00:00
Eelco Dolstra
6c9fdb17fb * Don't use $SHELL. 2007-02-21 14:00:46 +00:00
Eelco Dolstra
b824a1daee * Start of `nix-store --export' operation for serialising a store
path.  This is like `nix-store --dump', only it also dumps the
  meta-information of the store path (references, deriver).  Will add
  a `--sign' flag later to add a cryptographic signature, which we
  will use for exchanging store paths between build farm machines in a
  secure manner.
2007-02-20 23:17:20 +00:00
Eelco Dolstra
3390c1be76 * Temporary notes on how we're going to use OpenSSL. 2007-02-20 22:57:46 +00:00
Eelco Dolstra
8181a1c3bb * Close the file - just in case. 2007-02-20 22:49:08 +00:00
Eelco Dolstra
46605fb4f5 * Fix 64-bit compiler warnings. 2007-02-06 20:03:53 +00:00
Eelco Dolstra
52d03276dd * Compatibility with docbook5-xsl. 2007-02-05 12:10:10 +00:00
Eelco Dolstra
451dbf687f * nix-env now maintains meta info (from the `meta' derivation
attribute) about installed packages in user environments.  Thus, an
  operation like `nix-env -q --description' shows useful information
  not only on available packages but also on installed packages.

* nix-env now passes the entire manifest as an argument to the Nix
  expression of the user environment builder (not just a list of
  paths), so that in particular the user environment builder has
  access to the meta attributes.
  
* New operation `--set-flag' in nix-env to change meta info of
  installed packages.  This will be useful to pass per-package
  policies to the user environment builder (e.g., how to resolve
  collision or whether to disable a package (NIX-80)) or upgrade
  policies in nix-env (e.g., that a package should be "masked", that
  is, left untouched by upgrade actions).  Example:

  $ nix-env --set-flag enabled false ghc-6.4
2007-02-02 01:52:42 +00:00
Eelco Dolstra
f52de527c7 * Doh! 2007-01-29 15:55:49 +00:00
Eelco Dolstra
b618fa6eb6 * computeStorePathForText: take the references into account when
computing the store path (NIX-77).  This is an important security
  property in multi-user Nix stores.

  Note that this changes the store paths of derivations (since the
  derivation aterms are added using addTextToStore), but not most
  outputs (unless they use builtins.toFile).
2007-01-29 15:51:37 +00:00
Eelco Dolstra
c558b1583c * Don't capitalise the primop functions. 2007-01-29 15:15:37 +00:00
Eelco Dolstra
18e6096105 * Organise primops.cc a bit better. 2007-01-29 15:11:32 +00:00
Eelco Dolstra
7349bd0176 New primitives:
* `sub' to subtract two numbers.
* `stringLength' to get the length of a string.
* `substring' to get a substring of a string.  These should be enough
  to allow most string operations to be expressed.
2007-01-29 14:23:09 +00:00
Eelco Dolstra
7dedbd896a * filterSource: pass strings to the predicate function instead of
paths.  Paths can have unexpected semantics.
2007-01-29 13:32:50 +00:00
Eelco Dolstra
84a84afb0e * Nasty: Glibc clears the TMPDIR environment variable in setuid
programs, so if a builder uses TMPDIR, then it will fail when
  executed through nix-setuid-helper.  In fact Glibc clears a whole
  bunch of variables (see sysdeps/generic/unsecvars.h in the Glibc
  sources), but only TMPDIR should matter in practice.  As a
  workaround, we reinitialise TMPDIR from NIX_BUILD_TOP.
2007-01-24 13:31:20 +00:00
Eelco Dolstra
fac63d6416 * exportReferencesGraph: work on paths within store paths as well. 2007-01-23 16:57:43 +00:00
Eelco Dolstra
bae75ca5a1 * New kind of manifest object: "localPath", which denotes that a store
path can be created by copying it from another location in the file
  system.  This is useful in the NixOS installation.
2007-01-23 16:50:19 +00:00
Eelco Dolstra
36d9258c0d * Successors have been gone for ages. 2007-01-23 16:05:59 +00:00
Eelco Dolstra
7bc30e1ca8 * nix-prefetch-url: change the default hash to SHA-256 (in base-32). 2007-01-22 09:53:36 +00:00
Eelco Dolstra
71ceb1c161 * Handle multiple indirect symlinks when loading a Nix expression. 2007-01-15 14:50:25 +00:00
Eelco Dolstra
e4b0666f8e * builtins.filterSource: pass the type of the file ("regular",
"directory", "symlink") as the second argument to the filter
  predicate.
2007-01-15 08:54:51 +00:00
Eelco Dolstra
63f3ce6d9a * `nix-store --verify': revive checking the referrers table. This is
important to get garbage collection to work if there is any
  inconsistency in the database (because the referrer table is used to
  determine whether it is safe to delete a path).
* `nix-store --verify': show some progress.
2007-01-14 17:28:30 +00:00
Eelco Dolstra
8f67b35886 * Make the garbage collector more resilient to certain consistency
errors: in-use paths now cause a warning, not a fatal error.
2007-01-14 16:24:49 +00:00
Eelco Dolstra
8659edc098 * Don't forget the .flags files. 2007-01-14 12:33:04 +00:00
Eelco Dolstra
e418976107 * Option --argstr for passing string arguments easily. (NIX-75) 2007-01-14 12:32:44 +00:00
Eelco Dolstra
4e329f173f * Doh. 2007-01-14 12:16:58 +00:00
Eelco Dolstra
afe23b5f38 * nix-pack-closure: store the top-level store paths in the closure.
* nix-unpack-closure: extract the top-level paths from the closure and
  print them on stdout.  This allows them to be installed, e.g.,
  "nix-env -i $(nix-unpack-closure)".  (NIX-64)
2007-01-13 19:50:42 +00:00
Eelco Dolstra
f25f900045 * Allow multiple --attr / -A arguments in nix-build / nix-instantiate
(NIX-74).
2007-01-13 18:25:30 +00:00
Eelco Dolstra
215505bb46 * Removed chroot support. 2007-01-13 17:54:01 +00:00
Eelco Dolstra
f23dcdd603 * Canonicalise ASTs in `nix-instantiate --eval': remove position
info, sort attribute sets.
2007-01-13 16:17:07 +00:00
Eelco Dolstra
05879db628 * Memoize strict evaluation. 2007-01-13 15:41:54 +00:00
Eelco Dolstra
5011588459 * printTermAsXML: treat derivations specially; emit an element
<derivation outPath=... drvPath=...> attrs </derivation>.  Only emit
  the attributes of any specific derivation only.  This prevents
  exponententially large XML output due to the absense of sharing.
2007-01-13 15:11:10 +00:00
Eelco Dolstra
792878af91 * Make printing an expression as XML interruptible. 2007-01-13 14:48:41 +00:00
Eelco Dolstra
11158028be * Cleanup. 2007-01-13 14:21:49 +00:00
Eelco Dolstra
1b7840b949 2007-01-11 19:28:28 +00:00
Eelco Dolstra
69c8b5b8a7 * Install generate-patches into libexec. 2007-01-11 16:19:45 +00:00
Eelco Dolstra
1f3722bd4a * Reject patches that are larger than a certain fraction of the full archive
(currently 60%).  Large patches aren't very economical.
2007-01-08 15:32:15 +00:00
Eelco Dolstra
50bdec410a * Huge speedup in patch propagation (20 minutes or so to 3 seconds). 2007-01-08 15:17:18 +00:00
Eelco Dolstra
4c63f9fe04 * Another great success. 2006-12-29 22:23:51 +00:00
Eelco Dolstra
57969b95b3 * Testing 1 2 3. 2006-12-29 20:37:55 +00:00
Eelco Dolstra
cafaceb707 * Handle weird cases when the server redirects us while setting a cookie. 2006-12-15 21:27:26 +00:00
Eelco Dolstra
1073b1780a * Remove debug message. 2006-12-13 14:29:05 +00:00
Eelco Dolstra
a3e6415ba8 * New primop builtins.filterSource, which can be used to filter files
from a source directory.  All files for which a predicate function
  returns true are copied to the store.  Typical example is to leave
  out the .svn directory:

    stdenv.mkDerivation {
      ...
      src = builtins.filterSource
        (path: baseNameOf (toString path) != ".svn")
        ./source-dir;
      # as opposed to
      #   src = ./source-dir;
    }

  This is important because the .svn directory influences the hash in
  a rather unpredictable and variable way.
2006-12-12 23:05:01 +00:00
Eelco Dolstra
b438d37558 * In dumpPath(): pass a function object that allows files to be
selectively in/excluded from the dump.
2006-12-12 21:51:02 +00:00
Eelco Dolstra
3130f1f0fa * Push. 2006-12-12 20:17:14 +00:00
Eelco Dolstra
7ace29dae7 * New operation `nix-env --set' which sets a user environment to a
single derivation specified by the argument.  This is useful when we
  want to have a profile for a single derivation, such as a server
  configuration.  Then we can just say (e.g.)

  $ nix-env -p /.../server-profile -f server.nix --set -A server

  We can't do queries or upgrades on such a profile, but we can do
  rollbacks.  The advantage over -i is that we don't have to worry
  about other packages having been installed in the profile
  previously; --set gets rid of them.
2006-12-12 19:06:02 +00:00
Eelco Dolstra
1a7e88bbd9 * New built-in function `builtins.attrNames' that returns the
names of the attributes in an attribute set.
2006-12-12 16:14:31 +00:00
Eelco Dolstra
5e6699188f 2006-12-09 23:14:55 +00:00
Eelco Dolstra
b17677462c * Use lchown() instead of chown() in canonicalisePathMetaData(). This
matters when running as root, since then we don't use the setuid
  helper (which already used lchown()).
  
* Also check for an obscure security problem on platforms that don't
  have lchown.  Then we can't change the ownership of symlinks, which
  doesn't matter *except* when the containing directory is writable by
  the owner (which is the case with the top-level Nix store directory).
2006-12-09 20:02:27 +00:00
Eelco Dolstra
5f681988f2 * Use deletePathWrapped() in more places. 2006-12-09 00:26:24 +00:00
Eelco Dolstra
fa33303146 * Goal cancellation inside the waitForInput() loop needs to be handled
very carefully, since it can invalidate iterators into the
  `children' map.
2006-12-08 18:41:48 +00:00
Eelco Dolstra
06c4929958 * Some refactoring.
* Throw more exceptions as BuildErrors instead of Errors.  This
  matters when --keep-going is turned on.  (A BuildError is caught
  and terminates the goal in question, an Error terminates the
  program.)
2006-12-08 17:26:21 +00:00
Eelco Dolstra
9dbfe242e3 * Kill a build if it has gone for more than a certain number of
seconds without producing output on stdout or stderr (NIX-65).  This
  timeout can be specified using the `--max-silent-time' option or the
  `build-max-silent-time' configuration setting.  The default is
  infinity (0).

* Fix a tricky race condition: if we kill the build user before the
  child has done its setuid() to the build user uid, then it won't be
  killed, and we'll potentially lock up in pid.wait().  So also send a
  conventional kill to the child.
2006-12-08 15:44:00 +00:00
Eelco Dolstra
d3fe6ab024 * Also for convenience, change the ownership of the build output even
in case of failure.
2006-12-08 00:19:50 +00:00
Eelco Dolstra
096194ab29 * Remove ancient terminology. 2006-12-07 23:58:36 +00:00
Eelco Dolstra
6833e8bbe8 * When keeping the temporary build directory (-K), change the owner
back to the Nix account.
2006-12-07 23:27:40 +00:00
Eelco Dolstra
e24d0201c2 * Doh! 2006-12-07 22:07:05 +00:00
Eelco Dolstra
2819eb36a4 * Be less verbose. 2006-12-07 21:43:35 +00:00
Eelco Dolstra
4ca01065c3 * Rename all those main.cc files. 2006-12-07 20:47:30 +00:00
Eelco Dolstra
d03f0d4117 * Check for lchown. 2006-12-07 18:51:11 +00:00
Eelco Dolstra
c3286ec020 * Don't count on the Pid deconstructor to kill the child process,
since if we're running a build user in non-root mode, we can't.  Let
  the setuid helper do it.
2006-12-07 17:52:58 +00:00
Eelco Dolstra
a82d80ddeb * Move setuidCleanup() to libutil. 2006-12-07 16:40:41 +00:00
Eelco Dolstra
f76fdb6d42 * If not running as root, let the setuid helper kill the build user's
processes before and after the build.
2006-12-07 16:33:31 +00:00
Eelco Dolstra
ec23ecc64d * In the garbage collector, if deleting a path fails, try to fix its
ownership, then try again.
2006-12-07 15:54:52 +00:00
Eelco Dolstra
a0a43c3206 * When not running as root, call the setuid helper to change the
ownership of the build result after the build.
2006-12-07 15:18:14 +00:00
Eelco Dolstra
6a07ff1ec0 * Change the ownership of store paths to the Nix account before
deleting them using the setuid helper.
2006-12-07 14:14:35 +00:00
Eelco Dolstra
7d8cf316ee * Pass the actual build user to the setuid helper. 2006-12-07 11:27:32 +00:00
Eelco Dolstra
a45c498e4e * If Nix is not running as root, call the setuid helper to start the
builder under the desired build user.
2006-12-07 00:42:30 +00:00
Eelco Dolstra
813a7c65c9 * Sanity check. 2006-12-07 00:19:27 +00:00
Eelco Dolstra
6a8e60913a * Move killUser() to libutil so that the setuid helper can use it. 2006-12-07 00:16:07 +00:00
Eelco Dolstra
79875c5e42 * Change the ownership of the current directory to the build user. 2006-12-06 23:52:25 +00:00
Eelco Dolstra
62ab131412 * Verify that the desired target user is in the build users group (as
specified in the setuid config file).
2006-12-06 23:15:26 +00:00
Eelco Dolstra
f07ac41656 * Check that the caller is allowed to call the setuid helper. The
allowed uid is specified in a configuration file in
  /etc/nix-setuid.conf.
2006-12-06 22:45:41 +00:00
Eelco Dolstra
173d328351 * Urgh. 2006-12-06 20:19:25 +00:00
Eelco Dolstra
ef281b93c2 * Fix the safety check. 2006-12-06 20:18:29 +00:00
Eelco Dolstra
a14d491f09 * Oops. 2006-12-06 20:16:28 +00:00
Eelco Dolstra
6e5ec1029a * Get rid of `build-users'. We'll just take all the members of
`build-users-group'.  This makes configuration easier: you can just
  add users in /etc/group.
2006-12-06 20:00:15 +00:00
Eelco Dolstra
751f6d2157 * nix-setuid-helper: allow running programs under a different uid. 2006-12-06 17:29:10 +00:00
Eelco Dolstra
9f0efa6611 * Start of the setuid helper (the program that performs the operations
that have to be done as root: running builders under different uids,
  changing ownership of build results, and deleting paths in the store
  with the wrong ownership).
2006-12-06 01:24:02 +00:00
Eelco Dolstra
2b558843a2 * Be less chatty. 2006-12-05 19:01:19 +00:00
Eelco Dolstra
44cad9630f * Urgh. Do setgid() before setuid(), because the semantics of setgid()
changes completely depending on whether you're root...
2006-12-05 18:28:15 +00:00
Eelco Dolstra
6f0d050324 * Tricky: child processes should not send data to the client since
that might mess up the protocol.  And besides, the socket file
  descriptor is probably closed.
2006-12-05 18:21:16 +00:00
Eelco Dolstra
4c1c37d0b6 * FreeBSD returns ESRCH when there are no processes to kill. 2006-12-05 18:07:46 +00:00
Eelco Dolstra
8d1854c3f1 * Oops! In daemon mode, we can't run as root either if build-users is empty. 2006-12-05 17:44:19 +00:00
Eelco Dolstra
99655245ae * Use an explicit handler for SIGCHLD, since SIG_IGN doesn't do the
right thing on FreeBSD 4 (it leaves zombies).
2006-12-05 17:21:42 +00:00
Eelco Dolstra
62b0497c0f * Better message. 2006-12-05 16:17:01 +00:00
Eelco Dolstra
c808e6252f * Ugly hack to handle spurious SIGPOLLs. 2006-12-05 15:36:31 +00:00
Eelco Dolstra
fd4a9db91f * Some renaming. 2006-12-05 14:15:51 +00:00
Eelco Dolstra
fc1c20d11b * Redundant. 2006-12-05 13:57:35 +00:00
Eelco Dolstra
a9c4f66cfb * Allow unprivileged users to run the garbage collector and to do
`nix-store --delete'.  But unprivileged users are not allowed to
  ignore liveness.
* `nix-store --delete --ignore-liveness': ignore the runtime roots as
  well.
2006-12-05 02:18:46 +00:00
Eelco Dolstra
29cf434a35 * The determination of the root set should be made by the privileged
process, so forward the operation.
* Spam the user about GC misconfigurations (NIX-71).
* findRoots: skip all roots that are unreadable - the warnings with
  which we spam the user should be enough.
2006-12-05 01:31:45 +00:00
Eelco Dolstra
8623256f48 * findRoots: return a map from the symlink (outside of the store) to
the store path (inside the store).
2006-12-05 00:48:36 +00:00
Eelco Dolstra
d27a73b1a9 * In addPermRoot, check that the root that we just registered can be
found by the garbage collector.  This addresses NIX-71 and is a
  particular concern in multi-user stores.
2006-12-05 00:34:42 +00:00
Eelco Dolstra
74033a844f * Add indirect root registration to the protocol so that unprivileged
processes can register indirect roots.  Of course, there is still
  the problem that the garbage collector can only read the targets of
  the indirect roots when it's running as root...
2006-12-04 23:29:16 +00:00
Eelco Dolstra
0d40f6d7bb * Not every OS knows about SIGPOLL. 2006-12-04 22:58:44 +00:00
Eelco Dolstra
7751160e9f * Don't redirect stderr. 2006-12-04 19:10:23 +00:00
Eelco Dolstra
40c3529909 * Handle exceptions and stderr for all protocol functions.
* SIGIO -> SIGPOLL (POSIX calls it that).
* Use sigaction instead of signal to register the SIGPOLL handler.
  Sigaction is better defined, and a handler registered with signal
  appears not to interrupt fcntl(..., F_SETLKW, ...), which is bad.
2006-12-04 17:55:14 +00:00
Eelco Dolstra
0130ef88ea * Daemon mode (`nix-worker --daemon'). Clients connect to the server
via the Unix domain socket in /nix/var/nix/daemon.socket.  The
  server forks a worker process per connection.
* readString(): use the heap, not the stack.
* Some protocol fixes.
2006-12-04 17:17:13 +00:00
Eelco Dolstra
4740baf3a6 * When NIX_REMOTE=daemon, connect to /nix/var/nix/daemon.socket
instead of forking a worker.
2006-12-04 14:21:39 +00:00
Eelco Dolstra
f5f0cf423f * Refactoring. 2006-12-04 13:28:14 +00:00
Eelco Dolstra
052b6fb149 * Pass the verbosity level to the worker. 2006-12-04 13:15:29 +00:00
Eelco Dolstra
1e16d20655 * Install the worker in bindir, not libexecdir.
* Allow the worker path to be overriden through the NIX_WORKER
  environment variable.
2006-12-04 13:09:16 +00:00
Eelco Dolstra
9322b399f3 * Doh. 2006-12-03 20:41:22 +00:00
Eelco Dolstra
f4279bcde0 * Don't run setuid root when build-users is empty.
* Send startup errors to the client.
2006-12-03 16:25:19 +00:00
Eelco Dolstra
35247c4c9f * Removed `build-allow-root'.
* Added `build-users-group', the group under which builds are to be
  performed.
* Check that /nix/store has 1775 permission and is owner by the
  build-users-group.
2006-12-03 15:32:38 +00:00
Eelco Dolstra
84d6459bd5 * Use setreuid if setresuid is not available. 2006-12-03 14:32:22 +00:00
Eelco Dolstra
a9f9241054 * Handle a subtle race condition: the client closing the socket
between the last worker read/write and the enabling of the signal
  handler.
2006-12-03 03:16:27 +00:00
Eelco Dolstra
3ed9e4ad9b * Some hardcore magic to handle asynchronous client disconnects.
The problem is that when we kill the client while the worker is
  building, and the builder is not writing anything to stderr, then
  the worker never notice that the socket is closed on the other side,
  so it just continues indefinitely.  The solution is to catch SIGIO,
  which is sent when the far side of the socket closes, and simulate
  an normal interruption.  Of course, SIGIO is also sent every time
  the client sends data over the socket, so we only enable the signal
  handler when we're not expecting any data...
2006-12-03 03:03:36 +00:00
Eelco Dolstra
4251f94b32 * Use a Unix domain socket instead of pipes. 2006-12-03 02:36:44 +00:00
Eelco Dolstra
8c76df93e6 * Better error message if the worker doesn't start. 2006-12-03 02:22:04 +00:00
Eelco Dolstra
363f40022f * Pid::kill() should be interruptable. 2006-12-03 02:12:26 +00:00
Eelco Dolstra
7951c3c546 * Some hackery to propagate the worker's stderr and exceptions to the
client.
2006-12-03 02:08:13 +00:00
Eelco Dolstra
714fa24cfb * Run the worker in a separate session to prevent terminal signals
from interfering.
2006-12-03 00:52:27 +00:00
Eelco Dolstra
e25fad691a * Move addTempRoot() to the store API, and add another function
syncWithGC() to allow clients to register GC roots without needing
  write access to the global roots directory or the GC lock.
2006-12-02 16:41:36 +00:00
Eelco Dolstra
30bf547f4f * Doh. 2006-12-02 15:46:17 +00:00
Eelco Dolstra
536595b072 * Remove most of the old setuid code.
* Much simpler setuid code for the worker in slave mode.
2006-12-02 15:45:51 +00:00
Eelco Dolstra
9c9cdb06d0 * Remove SwitchToOriginalUser, we're not going to need it anymore. 2006-12-02 14:34:14 +00:00
Eelco Dolstra
626f8ee42f * Clear NIX_REMOTE in the tests. 2006-12-02 14:33:39 +00:00
Eelco Dolstra
8ba5d32769 * Remove queryPathHash().
* Help for nix-worker.
2006-12-02 14:27:24 +00:00
Eelco Dolstra
fcd9900d74 * Replace read-only calls to addTextToStore. 2006-12-01 21:00:39 +00:00
Eelco Dolstra
a824d58b56 * Merge addToStore and addToStoreFixed.
* addToStore now adds unconditionally, it doesn't use readOnlyMode.
  Read-only operation is up to the caller (who can call
  computeStorePathForPath).
2006-12-01 20:51:18 +00:00
Eelco Dolstra
ceb982a1be * Right name. 2006-12-01 18:02:05 +00:00
Eelco Dolstra
b0d8e05be1 * More operations.
* addToStore() and friends: don't do a round-trip to the worker if
  we're only interested in the path (i.e., in read-only mode).
2006-12-01 18:00:01 +00:00
Eelco Dolstra
0565b5f2b3 * More remote operations.
* Added new operation hasSubstitutes(), which is more efficient than
  querySubstitutes().size() > 0.
2006-11-30 22:43:55 +00:00
Eelco Dolstra
aac547a8b3 * Doh. 2006-11-30 21:32:46 +00:00
Eelco Dolstra
0263279071 * More operations. 2006-11-30 20:45:20 +00:00
Eelco Dolstra
a711689368 * First remote operation: isValidPath(). 2006-11-30 20:13:59 +00:00
Eelco Dolstra
765bdfe542 * When NIX_REMOTE is set to "slave", fork off nix-worker in slave
mode.  Presumably nix-worker would be setuid to the Nix store user.
  The worker performs all operations on the Nix store and database, so
  the caller can be completely unprivileged.

  This is already much more secure than the old setuid scheme, since
  the worker doesn't need to do Nix expression evaluation and so on.
  Most importantly, this means that it doesn't need to access any user
  files, with all resulting security risks; it only performs pure
  store operations.

  Once this works, it is easy to move to a daemon model that forks off
  a worker for connections established through a Unix domain socket.
  That would be even more secure.
2006-11-30 19:54:43 +00:00
Eelco Dolstra
40b3f64b55 * Skeleton of the privileged worker program.
* Some refactoring: put the NAR archive integer/string serialisation
  code in a separate file so it can be reused by the worker protocol
  implementation.
2006-11-30 19:19:59 +00:00
Eelco Dolstra
9adc074dc3 * Oops. 2006-11-30 18:35:50 +00:00
Eelco Dolstra
9cf1948993 * Skeleton of remote store implementation. 2006-11-30 18:35:36 +00:00
Eelco Dolstra
6ecb840fd1 * Put building in the store API. 2006-11-30 18:02:04 +00:00
Eelco Dolstra
e2ef5e07fd * Refactoring. There is now an abstract interface class StoreAPI
containing functions that operate on the Nix store.  One
  implementation is LocalStore, which operates on the Nix store
  directly.  The next step, to enable secure multi-user Nix, is to
  create a different implementation RemoteStore that talks to a
  privileged daemon process that uses LocalStore to perform the actual
  operations.
2006-11-30 17:43:04 +00:00
Eelco Dolstra
5f0b9de6d8 * Benchmarking Unix domain sockets. 2006-11-30 15:06:46 +00:00
Eelco Dolstra
fe15f991e3 * Troubleshooting information on fixing a b0rked Berkeley DB database. 2006-11-30 11:24:10 +00:00
Eelco Dolstra
80b742dd52 * Don't spam. 2006-11-29 22:07:49 +00:00
Roy van den Broek
92417600a1 * Example script to set permissions for setuid operation. 2006-11-29 21:58:09 +00:00
Eelco Dolstra
71e867c5f5 * Remove --enable-setuid, --with-nix-user and --with-nix-group.
Rather, setuid support is now always compiled in (at least on
  platforms that have the setresuid system call, e.g., Linux and
  FreeBSD), but it must enabled by chowning/chmodding the Nix
  binaries.
2006-11-29 21:06:58 +00:00
Eelco Dolstra
c6a97e3b74 * Doh! Path sizes need to be computed recursively of course.
(NIX-70)
2006-11-24 20:24:14 +00:00
Eelco Dolstra
a76efaeb3f * Dead files. 2006-11-24 20:07:30 +00:00
Eelco Dolstra
d941186289 * Show more progress. 2006-11-18 19:03:45 +00:00
Eelco Dolstra
0541ddc7e3 * Turn off synchronisation between C and C++ I/O functions. This
gives a huge speedup in operations that read or write from standard
  input/output.  (So libstdc++'s I/O isn't that bad, you just have to
  call std::ios::sync_with_stdio(false).)  For instance, `nix-store
  --register-substitutes' went from 1.4 seconds to 0.1 seconds on a
  certain input.  Another victory for Valgrind.
2006-11-18 18:56:30 +00:00
Eelco Dolstra
471749ca7e * Grrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrr... 2006-11-14 19:18:52 +00:00
Eelco Dolstra
17d18b1a9c * Doh! 2006-11-14 19:11:36 +00:00
Eelco Dolstra
0ddaee756e * Doh. 2006-11-14 19:08:46 +00:00
Eelco Dolstra
bce9ff7ece * Use the patched ATerm library. 2006-11-14 15:36:27 +00:00
Eelco Dolstra
745e354b19 * Push. 2006-11-14 10:23:21 +00:00
Eelco Dolstra
f459a5bb3a * Remove the undocumented `noscan' feature. It's no longer necessary
now that reference scanning is sufficiently streamy.
2006-11-13 18:19:05 +00:00
Eelco Dolstra
e2a70b7ec0 * Magic attribute `exportReferencesGraph' that allows the references
graph to be passed to a builder.  This attribute should be a list of
  pairs [name1 path1 name2 path2 ...].  The references graph of each
  `pathN' will be stored in a text file `nameN' in the temporary build
  directory.  The text files have the format used by `nix-store
  --register-validity'.  However, the deriver fields are left empty.

  `exportReferencesGraph' is useful for builders that want to do
  something with the closure of a store path.  Examples: the builders
  that make initrds and ISO images for NixOS.

  `exportReferencesGraph' is entirely pure.  It's necessary because
  otherwise the only way for a builder to get this information would
  be to call `nix-store' directly, which is not allowed (though
  unfortunately possible).
2006-11-13 18:18:13 +00:00
Eelco Dolstra
e40d4a5604 * Option --reregister' in nix-store --register-validity'. We need
this in the NixOS installer (or in the buildfarm) to ensure that the
  cryptographic hash of the path contents still matches the actual
  contents.
2006-11-13 16:48:27 +00:00
Eelco Dolstra
e790404318 * Don't use the result of `uname -p' on x86_64 as it gives wacky
results on some machines. (NIX-69)
2006-11-13 14:54:18 +00:00
Eelco Dolstra
983c5e3fce * Fix the locking patch for Berkeley DB 4.5. 2006-11-07 14:51:28 +00:00
Eelco Dolstra
7e85a2af5f * Fix importing of derivation outputs. 2006-11-03 16:17:39 +00:00
Eelco Dolstra
b3f916995a * Oops, `nix-build --no-out-link' was broken. 2006-10-31 18:45:17 +00:00
Eelco Dolstra
005eecfc4d * Release notes. 2006-10-30 16:29:05 +00:00
Eelco Dolstra
8478cd260f * readFile: don't overflow the stack on large files. 2006-10-30 11:56:09 +00:00
Eelco Dolstra
8d17265ac4 * Don't use EPSV. 2006-10-28 22:07:09 +00:00
Eelco Dolstra
ae6fb27f18 * `nix-store --read-log / -l PATH' shows the build log of PATH, if
available.  For instance,

    $ nix-store -l $(which svn) | less

  lets you read the build log of the Subversion instance in your
  profile.

* `nix-store -qb': if applied to a non-derivation, take the deriver.
2006-10-28 16:33:54 +00:00
Eelco Dolstra
99b0ea7c67 * Typo reported by Arie Middelkoop.
* Left out close-quote in example.
2006-10-26 23:06:47 +00:00
Eelco Dolstra
dd300fb48d * Some better error messages. 2006-10-23 16:45:19 +00:00
Eelco Dolstra
1d694eef4c * Require Perl 5.8.0 or newer. I mean, it *is* more than four years
old...
2006-10-19 19:20:18 +00:00
Eelco Dolstra
7a4497d98c * Checks for allowedReferences and some other features.
* Use nix-build in a test.
2006-10-19 17:44:51 +00:00
Eelco Dolstra
17f4883bfe * Better message. 2006-10-19 17:43:58 +00:00
Eelco Dolstra
9bd93f7606 * toFile: maintain the references. 2006-10-19 17:39:02 +00:00
Eelco Dolstra
b3d3700e11 * nix-build: check the exit status of `nix-store -r'. 2006-10-19 17:30:09 +00:00
Eelco Dolstra
6a67556f71 * Special derivation attribute `allowedReferences' that causes Nix to
check that the references of the output of a derivation are in the
  specified set.  For instance,

    allowedReferences = [];

  specifies that the output cannot have any references.  (This is
  useful, for instance, for the generation of bootstrap binaries for
  stdenv-linux, which must not have any references for purity).  It
  could also be used to guard against undesired runtime dependencies,
  e.g.,

    {gcc, dynlib}: derivation {
      ...
      allowedReferences = [dynlib];
    }

  says that the output can refer to the path of `dynlib' but not
  `gcc'.  A `forbiddedReferences' attribute would be more useful for
  this, though.
2006-10-19 16:09:24 +00:00
Eelco Dolstra
daa8f85fcd * Backwards compatibility hack for user environments made by Nix <= 0.10. 2006-10-17 14:13:15 +00:00
Eelco Dolstra
24737f279e * Backwards compatibility with old user environment manifests. 2006-10-17 14:01:45 +00:00
Eelco Dolstra
4bd5cdb90b * Print out the offending path. 2006-10-17 14:01:28 +00:00
Eelco Dolstra
58ff6939f4 * An awful backwards compatibility hack. 2006-10-17 12:58:42 +00:00
Eelco Dolstra
3059df0f1e * baseNameOf: paths don't have to be absolute. 2006-10-17 12:34:13 +00:00
Eelco Dolstra
822dba2210 * Maintain the references for the user environment properly. 2006-10-17 12:15:15 +00:00
Eelco Dolstra
dfc042a0c1 * Another test. 2006-10-17 11:16:02 +00:00
Eelco Dolstra
9e30694f98 * Fix the tests wrt the AST changes, i.e., Str(s) -> Str(s, []), and
the semantic changes.
2006-10-17 11:08:59 +00:00
Eelco Dolstra
be1961c9f8 * toPath: should be the identity on paths. 2006-10-17 11:07:11 +00:00
Eelco Dolstra
cba913c521 * dirOf: return a path if the argument is a path. 2006-10-17 11:05:34 +00:00
Eelco Dolstra
cf705eaf78 * toString: don't copy paths. So toString can be used to pass
non-store paths to a builder.
2006-10-17 10:58:12 +00:00
Eelco Dolstra
7de5fe2fc2 * Do the path check on the normal form. 2006-10-17 10:57:25 +00:00
Eelco Dolstra
46b631b6c4 * Don't generate an empty drvPath attribute in the manifest. 2006-10-17 10:15:42 +00:00
Eelco Dolstra
d7efd76394 * Big cleanup of the semantics of paths, strings, contexts, string
concatenation and string coercion.  This was a big mess (see
  e.g. NIX-67).  Contexts are now folded into strings, so that they
  don't cause evaluation errors when they're not expected.  The
  semantics of paths has been clarified (see nixexpr-ast.def).
  toString() and coerceToString() have been merged.

  Semantic change: paths are now copied to the store when they're in a
  concatenation (and in most other situations - that's the
  formalisation of the meaning of a path).  So

    "foo " + ./bla

  evaluates to "foo /nix/store/hash...-bla", not "foo
  /path/to/current-dir/bla".  This prevents accidental impurities, and
  is more consistent with the treatment of derivation outputs, e.g.,
  `"foo " + bla' where `bla' is a derivation.  (Here `bla' would be
  replaced by the output path of `bla'.)
2006-10-16 15:55:34 +00:00
Eelco Dolstra
4c9aa821b9 * Fix version. 2006-10-13 14:08:14 +00:00
Eelco Dolstra
142863a89d * Use Berkeley DB 4.5. 2006-10-13 12:11:30 +00:00
Eelco Dolstra
37c8a664f3 * A helpful message. 2006-10-13 11:49:55 +00:00
Eelco Dolstra
e4af398681 * Don't crash when upgrading the Berkeley DB environment. 2006-10-13 11:15:53 +00:00
Eelco Dolstra
2a535689fe * Reduce the maximum archive size for patch generation to 100 MB to
prevent trashing on nix.cs.uu.nl.
2006-10-12 20:13:29 +00:00
Eelco Dolstra
7d4567f2cc * Removed URIs from the evaluator (NIX-66). They are now just another
kind of notation for strings.
2006-10-11 21:59:33 +00:00
Eelco Dolstra
b4e012ab4d * Merge 0.10.1 release notes. 2006-10-11 13:39:00 +00:00
Eelco Dolstra
0c4c5c2020 * Quick hack to fix NIX-67: evaluation result differing if the Nix
expression resides in the store.
2006-10-10 21:23:35 +00:00
Eelco Dolstra
bd0c40e1e9 * import': unwrap the context. Necessary to make import (x + y)'
work, where x is a store path.
2006-10-10 15:07:23 +00:00
Eelco Dolstra
7bada48b36 * Bumped the version number to 0.11. 2006-10-06 13:45:29 +00:00
242 changed files with 18800 additions and 6123 deletions

View File

@@ -20,10 +20,11 @@ install-data-local: init-state
fi
if INIT_STATE
if SETUID_HACK
INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
GROUP_WRITABLE = -m 775
endif
# For setuid operation, you can enable the following:
# INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
# GROUP_WRITABLE = -m 775
init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/db
@@ -34,19 +35,26 @@ init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/temproots
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/gcroots/tmp
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/gcroots/channels
rm -f $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
ln -s $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
ln -sfn $(localstatedir)/nix/profiles $(DESTDIR)$(localstatedir)/nix/gcroots/profiles
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/userpool
$(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(prefix)/store
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
ln -sfn $(localstatedir)/nix/manifests $(DESTDIR)$(localstatedir)/nix/gcroots/manifests
# $(bindir)/nix-store --init
else
init-state:
endif
init-ext3cow-header-hack:
@echo "Symlinking ext3cow header file into src"
ln -sf $(ext3cowheader) src/libext3cow/
svn-revision:
svnversion . > svn-revision
all: init-ext3cow-header-hack
all-local: NEWS
NEWS: doc/manual/NEWS.txt

3
TODO Normal file
View File

@@ -0,0 +1,3 @@
- runtimeStateArgs now must be set to someting (or it will see it as a hardcoded path)
- import and export of state paths
-

View File

@@ -1,6 +1,6 @@
#! /bin/sh -e
mkdir -p config
libtoolize --copy
libtoolize --force --copy
aclocal
autoheader
automake --add-missing --copy

View File

@@ -1,4 +1,4 @@
AC_INIT(nix, 0.10)
AC_INIT(nix, 0.12)
AC_CONFIG_SRCDIR(README)
AC_CONFIG_AUX_DIR(config)
AM_INIT_AUTOMAKE([dist-bzip2 foreign])
@@ -9,14 +9,14 @@ STABLE=0
# Put the revision number in the version.
if test "$STABLE" != "1"; then
if REVISION=`test -d $srcdir/.svn && svnversion $srcdir 2> /dev/null`; then
if REVISION=`test -d $srcdir/.svn && svnversion -n $srcdir 2> /dev/null`; then
VERSION=${VERSION}pre${REVISION}
elif REVISION=`cat $srcdir/svn-revision 2> /dev/null`; then
VERSION=${VERSION}pre${REVISION}
fi
fi
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$(echo $VERSION)"], [version])
AC_DEFINE_UNQUOTED(NIX_VERSION, ["$VERSION"], [version])
AC_PREFIX_DEFAULT(/nix)
@@ -32,6 +32,9 @@ case $machine_name in
i*86)
machine_name=i686
;;
x86_64)
machine_name=x86_64
;;
ppc)
machine_name=powerpc
;;
@@ -96,9 +99,19 @@ static char buf[1024];]],
AC_LANG_POP(C++)
# Check for chroot support (requires chroot() and bind mounts).
AC_CHECK_FUNCS([chroot])
AC_CHECK_HEADERS([sys/param.h], [], [], [])
AC_CHECK_HEADERS([sys/mount.h], [], [],
[#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
])
# Check for <locale>
AC_LANG_PUSH(C++)
AC_CHECK_HEADERS([locale])
AC_CHECK_HEADERS([locale], [], [], [])
AC_LANG_POP(C++)
@@ -111,7 +124,7 @@ fi
])
NEED_PROG(curl, curl)
NEED_PROG(shell, sh)
NEED_PROG(shell, bash)
NEED_PROG(patch, patch)
AC_PATH_PROG(xmllint, xmllint, false)
AC_PATH_PROG(xsltproc, xsltproc, false)
@@ -122,8 +135,22 @@ AC_PATH_PROG(bison, bison, false)
NEED_PROG(perl, perl)
NEED_PROG(tar, tar)
AC_PATH_PROG(dot, dot)
AC_PATH_PROG(dblatex, dblatex)
AC_PATH_PROG(openssl_prog, openssl, openssl) # if not found, call openssl in $PATH
AC_SUBST(openssl_prog)
AC_DEFINE_UNQUOTED(OPENSSL_PATH, ["$openssl_prog"], [Path of the OpenSSL binary])
# Test that Perl has the open/fork feature (Perl 5.8.0 and beyond).
AC_MSG_CHECKING([whether Perl is recent enough])
if ! $perl -e 'open(FOO, "-|", "true"); while (<FOO>) { print; }; close FOO or die;'; then
AC_MSG_RESULT(no)
AC_MSG_ERROR([Your Perl version is too old. Nix requires Perl 5.8.0 or newer.])
fi
AC_MSG_RESULT(yes)
NEED_PROG(cat, cat)
NEED_PROG(tr, tr)
AC_ARG_WITH(coreutils-bin, AC_HELP_STRING([--with-coreutils-bin=PATH],
[path of cat, mkdir, etc.]),
coreutils=$withval, coreutils=$(dirname $cat))
@@ -149,6 +176,11 @@ AC_ARG_WITH(store-dir, AC_HELP_STRING([--with-store-dir=PATH],
storedir=$withval, storedir='${prefix}/store')
AC_SUBST(storedir)
AC_ARG_WITH(store-state-dir, AC_HELP_STRING([--with-store-state-dir=PATH],
[path of the Nix state store]),
storestatedir=$withval, storestatedir='${prefix}/state')
AC_SUBST(storestatedir)
AC_ARG_WITH(bdb, AC_HELP_STRING([--with-bdb=PATH],
[prefix of Berkeley DB]),
bdb=$withval, bdb=)
@@ -163,6 +195,18 @@ fi
AC_SUBST(bdb_lib)
AC_SUBST(bdb_include)
AC_ARG_WITH(ext3cow-header, AC_HELP_STRING([--with-ext3cow-header=PATH],
[path of the ext3cow header ext3cow_fs.h]),
ext3cowheader=$withval, ext3cowheader=)
AC_SUBST(ext3cowheader)
AC_CHECK_HEADER(${ext3cowheader})
NEED_PROG(rsync, rsync)
AC_ARG_WITH(rsync, AC_HELP_STRING([--with-rsync=PATH],
[path to the rsync binary.]),
rsync=$withval)
AC_SUBST(rsync)
AC_ARG_WITH(aterm, AC_HELP_STRING([--with-aterm=PATH],
[prefix of CWI ATerm library]),
aterm=$withval, aterm=)
@@ -226,33 +270,13 @@ AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
# Setuid installations.
AC_ARG_ENABLE(setuid, AC_HELP_STRING([--enable-setuid],
[install Nix setuid]),
setuid_hack=$enableval, setuid_hack=no)
AM_CONDITIONAL(SETUID_HACK, test "$setuid_hack" = "yes")
if test "$setuid_hack" = "yes"; then
AC_DEFINE(SETUID_HACK, 1, [whether to install Nix setuid])
fi
AC_CHECK_FUNCS([setresuid setreuid lchown])
AC_CHECK_FUNC(setresuid, [HAVE_SETRESUID=1], [HAVE_SETRESUID=])
AM_CONDITIONAL(HAVE_SETRESUID, test "$HAVE_SETRESUID" = "1")
if test "$HAVE_SETRESUID" = "1"; then
AC_DEFINE(HAVE_SETRESUID, 1, [whether we have setresuid()])
fi
AC_ARG_WITH(nix-user, AC_HELP_STRING([--with-nix-user=USER],
[user for Nix setuid binaries]),
NIX_USER=$withval, NIX_USER=nix)
AC_SUBST(NIX_USER)
AC_DEFINE_UNQUOTED(NIX_USER, ["$NIX_USER"], [Nix user])
AC_ARG_WITH(nix-group, AC_HELP_STRING([--with-nix-group=USER],
[group for Nix setuid binaries]),
NIX_GROUP=$withval, NIX_GROUP=nix)
AC_SUBST(NIX_GROUP)
AC_DEFINE_UNQUOTED(NIX_GROUP, ["$NIX_GROUP"], [Nix group])
# Nice to have, but not essential.
AC_CHECK_FUNCS([strsignal])
# This is needed if ATerm, Berkeley DB or bzip2 are static libraries,
# and the Nix libraries are dynamic.
if test "$(uname)" = "Darwin"; then
@@ -270,11 +294,15 @@ AC_CONFIG_FILES([Makefile
src/libutil/Makefile
src/libstore/Makefile
src/libmain/Makefile
src/libext3cow/Makefile
src/nix-store/Makefile
src/nix-state/Makefile
src/nix-hash/Makefile
src/libexpr/Makefile
src/nix-instantiate/Makefile
src/nix-env/Makefile
src/nix-worker/Makefile
src/nix-setuid-helper/Makefile
src/nix-log2xml/Makefile
src/bsdiff-4.3/Makefile
scripts/Makefile

View File

@@ -3,22 +3,39 @@
use strict;
use Cwd;
use IO::Handle;
use Fcntl;
STDOUT->autoflush(1);
my $out = $ENV{"out"};
mkdir "$out", 0755 || die "error creating $out";
sub readlink_or_StateWrapper;
my $symlinks = 0;
my %path_state_identifier = ();
my %priorities;
my $nixBinDir = $ENV{"nixBinDir"};
my $nixStore = $ENV{"nixStore"};
# For each activated package, create symlinks.
sub createLinks {
my $srcDir = shift;
#Lookup each $stateIdentifiers in $path_state_identifier
#we strip $srcDir to its rootdir e.g. /nix/store/......./
my @srcDirParts = split /\// , substr($srcDir, length ($nixStore), length ($srcDir));
my $srcDirRoot = $nixStore . "/" . $srcDirParts[1];
# print "srcDirRoot $srcDirRoot \n";
my $dstDir = shift;
my $ignoreCollisions = shift;
my $priority = shift;
my $pkgStateIdentifier = $path_state_identifier{$srcDirRoot}; # We have to look it up each time since recursion can change the $srcDir, but not the identifier
#print "createLinks $srcDir to $dstDir with iden $pkgStateIdentifier \n";
my @srcFiles = glob("$srcDir/*");
@@ -27,22 +44,23 @@ sub createLinks {
$baseName =~ s/^.*\///g; # strip directory
my $dstFile = "$dstDir/$baseName";
# Urgh, hacky...
if ($srcFile =~ /\/propagated-build-inputs$/ ||
# Urgh, hacky...
if ($srcFile =~ /\/propagated-build-inputs$/ ||
$srcFile =~ /\/nix-support$/ ||
$srcFile =~ /\/perllocal.pod$/ ||
$srcFile =~ /\/info\/dir$/ ||
$srcFile =~ /\/log$/)
{
# Do nothing.
}
}
elsif (-d $srcFile) {
lstat $dstFile;
#go recursive on directorys
if (-d _) {
createLinks($srcFile, $dstFile, $ignoreCollisions);
createLinks($srcFile, $dstFile, $priority);
}
elsif (-l _) {
@@ -51,31 +69,85 @@ sub createLinks {
die "collission between directory `$srcFile' and non-directory `$target'";
}
unlink $dstFile or die "error unlinking `$dstFile': $!";
mkdir $dstFile, 0755 ||
die "error creating directory `$dstFile': $!";
createLinks($target, $dstFile, $ignoreCollisions);
createLinks($srcFile, $dstFile, $ignoreCollisions);
mkdir $dstFile, 0755 || die "error creating directory `$dstFile': $!";
createLinks($target, $dstFile, $priorities{$dstFile});
createLinks($srcFile, $dstFile, $priority);
}
else {
#print "1ST DIR LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
symlink($srcFile, $dstFile) ||
die "error creating link `$dstFile': $!";
$priorities{$dstFile} = $priority;
$symlinks++;
}
}
elsif (-l $dstFile) {
if (!$ignoreCollisions) {
my $target = readlink $dstFile;
die "collission between `$srcFile' and `$target'";
}
}
else {
symlink($srcFile, $dstFile) ||
die "error creating link `$dstFile': $!";
$symlinks++;
}
# print "ELSE LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
# if we have a state component with a identifier different then ""
if($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier ne ""){
my @pathparts = split /\// , $srcFile;
my $parentDir = $pathparts[scalar(@pathparts) - 2];
if( $parentDir eq "bin" || $parentDir eq "sbin"){ #hacky....
print "STATELINK $srcFile to $dstFile - $pkgStateIdentifier \n";
my $new_dstFile;
my $new_stateIdentifier;
if($pkgStateIdentifier eq "__EMTPY__"){
$new_dstFile = $dstFile;
$new_stateIdentifier = "";
}
else{
$new_dstFile = "$dstFile-$pkgStateIdentifier";
$new_stateIdentifier = $pkgStateIdentifier;
}
# We also check with -e if the wrapperscript-file exists, and if is it a symlink (with -l)
if (-l $new_dstFile || -e $new_dstFile) {
my $target = readlink_or_StateWrapper $new_dstFile;
die "(state) collission between `$srcFile' and `$target' (over $new_dstFile)";
}
sysopen (DSTFILEHANDLE, $new_dstFile, O_RDWR|O_EXCL|O_CREAT, 0755);
printf DSTFILEHANDLE "#! @shell@ \n";
printf DSTFILEHANDLE "$nixBinDir/nix-state --run --identifier=$new_stateIdentifier $srcFile \"\$@\" \n";
close (DSTFILEHANDLE);
}
}
elsif($pkgStateIdentifier ne "__NOSTATE__" && $pkgStateIdentifier eq ""){ #TODO we now dont create symlinks for state packages with a empty identifier
#TODO but we must do it if there is no normal non-state pacakge
}
else {
if (-l $dstFile || -e $dstFile) {
my $target = readlink_or_StateWrapper $dstFile;
my $prevPriority = $priorities{$dstFile};
die ( "Collission between `$srcFile' and `$target'. "
. "Suggested solution: use `nix-env --set-flag "
. "priority NUMBER PKGNAME' to change the priority of "
. "one of the conflicting packages.\n" )
if $prevPriority == $priority;
next if $prevPriority < $priority;
unlink $dstFile or die;
}
# print "2ND LINK $srcFile to $dstFile with iden $pkgStateIdentifier \n";
symlink($srcFile, $dstFile) ||
die "error creating link `$dstFile': $!";
$priorities{$dstFile} = $priority;
$symlinks++;
}
}
}
}
@@ -86,13 +158,13 @@ my %postponed;
sub addPkg;
sub addPkg {
my $pkgDir = shift;
my $ignoreCollisions = shift;
my $priority = shift;
return if (defined $done{$pkgDir});
$done{$pkgDir} = 1;
# print "symlinking $pkgDir\n";
createLinks("$pkgDir", "$out", $ignoreCollisions);
createLinks("$pkgDir", "$out", $priority);
my $propagatedFN = "$pkgDir/nix-support/propagated-user-env-packages";
if (-e $propagatedFN) {
@@ -106,12 +178,56 @@ sub addPkg {
}
}
sub readlink_or_StateWrapper {
# Symlink to the packages that have been installed explicitly by the user.
my @args = split ' ', $ENV{"derivations"};
my $src = shift;
my $target;
foreach my $pkgDir (sort @args) {
addPkg($pkgDir, 0);
if (-l $src)
{ $target = readlink $src; }
else{
open(DAT, $src) || die("Could not open file!");
my @raw_data=<DAT>;
close(DAT);
$target = $raw_data[1];
}
return $target
}
my @stateIdentifiers = split ' ', $ENV{"stateIdentifiers"};
my $si_counter = 0;
# Convert the stuff we get from the environment back into a coherent
# data type.
my @paths = split ' ', $ENV{"paths"};
my @active = split ' ', $ENV{"active"};
my @priority = split ' ', $ENV{"priority"};
die if scalar @paths != scalar @active;
die if scalar @paths != scalar @priority;
my %pkgs;
for (my $n = 0; $n < scalar @paths; $n++) {
$pkgs{$paths[$n]} =
{ active => $active[$n]
, priority => $priority[$n]
, stateidentifier => $stateIdentifiers[$n]
};
$path_state_identifier{$paths[$n]} = $stateIdentifiers[$n];
}
# Symlink to the packages that have been installed explicitly by the
# user.
foreach my $pkg (sort (keys %pkgs)) {
#print "SP: $pkg \n";
#print "SI: $pkgs{$pkg}->{stateidentifier} \n";
#print "PR: $pkgs{$pkg}->{priority} \n";
addPkg($pkg, $pkgs{$pkg}->{priority}) if $pkgs{$pkg}->{active} ne "false";
$si_counter++;
}
@@ -119,16 +235,17 @@ foreach my $pkgDir (sort @args) {
# installed by the user (i.e., package X declares that it want Y
# installed as well). We do these later because they have a lower
# priority in case of collisions.
my $priorityCounter = 1000; # don't care about collisions
while (scalar(keys %postponed) > 0) {
my @pkgDirs = keys %postponed;
%postponed = ();
foreach my $pkgDir (sort @pkgDirs) {
addPkg($pkgDir, 1);
addPkg($pkgDir, $priorityCounter++);
}
}
print STDERR "created $symlinks symlinks in user environment\n";
symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";

View File

@@ -1,9 +1,16 @@
{system, derivations, manifest}:
{system, derivations, stateIdentifiers, manifest, nixBinDir, nixStore}:
derivation {
name = "user-environment";
system = system;
builder = ./builder.pl;
derivations = derivations;
stateIdentifiers = stateIdentifiers;
manifest = manifest;
inherit nixBinDir nixStore;
# !!! grmbl, need structured data for passing this in a clean way.
paths = derivations;
active = map (x: if x ? meta && x.meta ? active then x.meta.active else "true") derivations;
priority = map (x: if x ? meta && x.meta ? priority then x.meta.priority else "5") derivations;
}

View File

@@ -4,19 +4,23 @@
@coreutils@/mkdir $out/tmp
cd $out/tmp
expr=$out/default.nix
echo '[' > $expr
inputs=($inputs)
for ((n = 0; n < ${#inputs[*]}; n += 2)); do
channelName=${inputs[n]}
channelTarball=${inputs[n+1]}
echo "unpacking channel $channelName"
@bunzip2@ < $channelTarball | @tar@ xf -
nr=0
for i in $inputs; do
echo "unpacking $i"
@bunzip2@ < $i | @tar@ xf -
@coreutils@/mv * ../$nr # !!! hacky
echo "(import ./$nr)" >> $expr
nr=$(($nr + 1))
nr=1
attrName=$(echo $channelName | @tr@ -- '- ' '__')
dirName=$attrName
while test -e ../$dirName; do
nr=$((nr+1))
dirName=$attrName-$nr
done
@coreutils@/mv * ../$dirName # !!! hacky
done
echo ']' >> $expr
cd ..
@coreutils@/rmdir tmp

21
createRelease.sh Executable file
View File

@@ -0,0 +1,21 @@
#! /bin/sh -e
dir1=releases
dir2=nix-state
mkdir -p $dir1
cd $dir1
rm -rf $dir2
mkdir -p $dir2
cd $dir2
svn co https://svn.cs.uu.nl:12443/repos/trace/nix/branches/state ./
revision=`svn info | grep ^Revision | sed 's/Revision: //g'`
cd ..
date=`date +%Y%m%d`
tarfile=snix-${date}-rev${revision}.tar.gz
tar -cvf $tarfile \
--preserve-permissions \
--atime-preserve \
--gzip \
--verbose \
--no-ignore-command-error \
$dir2/

View File

@@ -1 +1 @@
SUBDIRS = manual
SUBDIRS =

View File

@@ -1,5 +1,8 @@
To produce a `stable' release from the trunk:
-1. Update the release notes; make sure that the release date is
correct.
0. Make sure that the trunk builds in the release supervisor.
1. Branch the trunk, e.g., `svn cp .../trunk
@@ -22,8 +25,8 @@ To produce a `stable' release from the trunk:
branch (e.g., `.../branches/0.5') should be created from the
original revision of the trunk (since maintenance releases should
also be tested first; hence, we cannot have `STABLE=1'). The same
procedure can then be followed to produce maintenance release; just
substitute `.../branches/VERSION' for the trunk.
procedure can then be followed to produce maintenance releases;
just substitute `.../branches/VERSION' for the trunk.
7. Switch back to the trunk.

View File

@@ -15,12 +15,12 @@ man1_MANS = nix-env.1 nix-build.1 nix-store.1 nix-instantiate.1 \
nix-collect-garbage.1 nix-push.1 nix-pull.1 \
nix-prefetch-url.1 nix-channel.1 \
nix-pack-closure.1 nix-unpack-closure.1 \
nix-install-package.1 nix-hash.1
nix-install-package.1 nix-hash.1 nix-copy-closure.1
FIGURES = figures/user-environments.png
MANUAL_SRCS = manual.xml introduction.xml installation.xml \
package-management.xml writing-nix-expressions.xml \
package-management.xml writing-nix-expressions.xml builtins.xml \
build-farm.xml \
$(man1_MANS:.1=.xml) \
troubleshooting.xml bugs.xml opt-common.xml opt-common-syn.xml \
@@ -31,7 +31,7 @@ MANUAL_SRCS = manual.xml introduction.xml installation.xml \
manual.is-valid: $(MANUAL_SRCS) version.txt
# $(XMLLINT) --xinclude $< | $(XMLLINT) --noout --nonet --relaxng $(docbookrng)/docbook.rng -
if test "$(jing)" != "false"; then \
$(XMLLINT) --xinclude $< | $(jing) $(docbookrng)/docbook.rng /dev/stdin; \
$(XMLLINT) --xinclude $< | $(jing) $(docbookrng)/docbook.rng /dev/fd/0; \
else \
echo "Not validating."; \
fi
@@ -47,6 +47,14 @@ manual.html: $(MANUAL_SRCS) manual.is-valid images
$(XSLTPROC) --nonet --xinclude --output manual.html \
$(docbookxsl)/html/docbook.xsl manual.xml
manual.pdf: $(MANUAL_SRCS) manual.is-valid images
if test "$(dblatex)" != ""; then \
$(dblatex) manual.xml; \
else \
echo "Please install dblatex and rerun configure."; \
exit 1; \
fi
NEWS_OPTS = \
--stringparam generate.toc "article nop" \

1
doc/manual/NEWS.txt Normal file
View File

@@ -0,0 +1 @@
New state nix version by wouter ...

View File

@@ -15,18 +15,6 @@ generation 43 is created which is a descendant of 39, not 42. So a
rollback from 43 ought to go back to 39. This is not currently
implemented; generations form a linear sequence.</para></listitem>
<listitem><para><emphasis>Build management.</emphasis> In principle it
is already possible to do build management using Nix (by writing
builders that perform appropriate build steps), but the Nix expression
language is not yet powerful enough to make this pleasant (?). The
language should be extended with features from the <link
xlink:href='http://www.cs.uu.nl/~eelco/maak/'>Maak build
manager</link>. Another interesting idea is to write a
<command>make</command> implementation that uses Nix as a back-end to
support <link
xlink:href='http://www.research.att.com/~bs/bs_faq.html#legacy'>legacy</link>
build files.</para></listitem>
<listitem><para>For security, <command>nix-push</command> manifests
should be digitally signed, and <command>nix-pull</command> should
verify the signatures. The actual NAR archives in the cache do not

View File

@@ -36,10 +36,10 @@ build farm, since:
builds, and Nix expressions are self-contained.</para></listitem>
<listitem><para>Nix will only rebuild things that have actually
changed. For instance, if the sources of a component haven't
changed between runs of the build farm, the component won't be
rebuild (unless it was garbage-collected). Also, dependencies
typically don't change very often, so they only need to be built
changed. For instance, if the sources of a package haven't changed
between runs of the build farm, the package won't be rebuilt (unless
it was garbage-collected). Also, dependencies typically don't
change very often, so they only need to be built
once.</para></listitem>
<listitem><para>The results of a Nix build farm can be made

760
doc/manual/builtins.xml Normal file
View File

@@ -0,0 +1,760 @@
<section xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id='ssec-builtins'>
<title>Built-in functions</title>
<para>This section lists the functions and constants built into the
Nix expression evaluator. (The built-in function
<function>derivation</function> is discussed above.) Some built-ins,
such as <function>derivation</function>, are always in scope of every
Nix expression; you can just access them right away. But to prevent
polluting the namespace too much, most built-ins are not in scope.
Instead, you can access them through the <varname>builtins</varname>
built-in value, which is an attribute set that contains all built-in
functions and values. For instance, <function>derivation</function>
is also available as <function>builtins.derivation</function>.</para>
<variablelist>
<varlistentry><term><function>abort</function> <replaceable>s</replaceable></term>
<listitem><para>Abort Nix expression evaluation, print error
message <replaceable>s</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.add</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the sum of the integers
<replaceable>e1</replaceable> and
<replaceable>e2</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.attrNames</function>
<replaceable>attrs</replaceable></term>
<listitem><para>Return the names of the attributes in the
attribute set <replaceable>attrs</replaceable> in a sorted list.
For instance, <literal>builtins.attrNames {y = 1; x =
"foo";}</literal> evaluates to <literal>["x" "y"]</literal>.
There is no built-in function <function>attrValues</function>, but
you can easily define it yourself:
<programlisting>
attrValues = attrs: map (name: builtins.getAttr name attrs) (builtins.attrNames attrs);</programlisting>
</para></listitem>
</varlistentry>
<varlistentry><term><function>baseNameOf</function> <replaceable>s</replaceable></term>
<listitem><para>Return the <emphasis>base name</emphasis> of the
string <replaceable>s</replaceable>, that is, everything following
the final slash in the string. This is similar to the GNU
<command>basename</command> command.</para></listitem>
</varlistentry>
<varlistentry><term><varname>builtins</varname></term>
<listitem><para>The attribute set <varname>builtins</varname>
contains all the built-in functions and values. You can use
<varname>builtins</varname> to test for the availability of
features in the Nix installation, e.g.,
<programlisting>
if builtins ? getEnv then builtins.getEnv "PATH" else ""</programlisting>
This allows a Nix expression to fall back gracefully on older Nix
installations that dont have the desired built-in function.
However, in that case you should not write
<programlisting>
if builtins ? getEnv then __getEnv "PATH" else ""</programlisting>
This Nix expression will trigger an “undefined variable” error on
older Nix versions since <function>__getEnv</function> doesnt
exist. <literal>builtins.getEnv</literal>, on the other hand, is
safe since <literal>builtins</literal> always exists and attribute
selection is lazy, so its only performed if the test
succeeds.</para></listitem>
</varlistentry>
<varlistentry
xml:id='builtin-currentSystem'><term><varname>builtins.currentSystem</varname></term>
<listitem><para>The built-in value <varname>currentSystem</varname>
evaluates to the Nix platform identifier for the Nix installation
on which the expression is being evaluated, such as
<literal>"i686-linux"</literal> or
<literal>"powerpc-darwin"</literal>.</para></listitem>
</varlistentry>
<!--
<varlistentry><term><function>currentTime</function></term>
<listitem><para>The built-in value <varname>currentTime</varname>
returns the current system time in seconds since 00:00:00 1/1/1970
UTC. Due to the evaluation model of Nix expressions
(<emphasis>maximal laziness</emphasis>), it always yields the same
value within an execution of Nix.</para></listitem>
</varlistentry>
-->
<!--
<varlistentry><term><function>dependencyClosure</function></term>
<listitem><para>TODO</para></listitem>
</varlistentry>
-->
<varlistentry><term><function>derivation</function>
<replaceable>attrs</replaceable></term>
<listitem><para><function>derivation</function> is described in
<xref linkend='ssec-derivation' />.</para></listitem>
</varlistentry>
<varlistentry><term><function>dirOf</function> <replaceable>s</replaceable></term>
<listitem><para>Return the directory part of the string
<replaceable>s</replaceable>, that is, everything before the final
slash in the string. This is similar to the GNU
<command>dirname</command> command.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.filterSource</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem>
<para>This function allows you to copy sources into the Nix
store while filtering certain files. For instance, suppose that
you want to use the directory <filename>source-dir</filename> as
an input to a Nix expression, e.g.
<programlisting>
stdenv.mkDerivation {
...
src = ./source-dir;
}
</programlisting>
However, if <filename>source-dir</filename> is a Subversion
working copy, then all those annoying <filename>.svn</filename>
subdirectories will also be copied to the store. Worse, the
contents of those directories may change a lot, causing lots of
spurious rebuilds. With <function>filterSource</function> you
can filter out the <filename>.svn</filename> directories:
<programlisting>
src = builtins.filterSource
(path: type: type != "directory" || baseNameOf path != ".svn")
./source-dir;
</programlisting>
</para>
<para>Thus, the first argument <replaceable>e1</replaceable>
must be a predicate function that is called for each regular
file, directory or symlink in the source tree
<replaceable>e2</replaceable>. If the function returns
<literal>true</literal>, the file is copied to the Nix store,
otherwise it is omitted. The function is called with two
arguments. The first is the full path of the file. The second
is a string that identifies the type of the file, which is
either <literal>"regular"</literal>,
<literal>"directory"</literal>, <literal>"symlink"</literal> or
<literal>"unknown"</literal> (for other kinds of files such as
device nodes or fifos — but note that those cannot be copied to
the Nix store, so if the predicate returns
<literal>true</literal> for them, the copy will fail).</para>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.getAttr</function>
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
<listitem><para><function>getAttr</function> returns the attribute
named <replaceable>s</replaceable> from the attribute set
<replaceable>attrs</replaceable>. Evaluation aborts if the
attribute doesnt exist. This is a dynamic version of the
<literal>.</literal> operator, since <replaceable>s</replaceable>
is an expression rather than an identifier.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.getEnv</function>
<replaceable>s</replaceable></term>
<listitem><para><function>getEnv</function> returns the value of
the environment variable <replaceable>s</replaceable>, or an empty
string if the variable doesnt exist. This function should be
used with care, as it can introduce all sorts of nasty environment
dependencies in your Nix expression.</para>
<para><function>getEnv</function> is used in Nix Packages to
locate the file <filename>~/.nixpkgs/config.nix</filename>, which
contains user-local settings for Nix Packages. (That is, it does
a <literal>getEnv "HOME"</literal> to locate the users home
directory.)</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.hasAttr</function>
<replaceable>s</replaceable> <replaceable>attrs</replaceable></term>
<listitem><para><function>hasAttr</function> returns
<literal>true</literal> if the attribute set
<replaceable>attrs</replaceable> has an attribute named
<replaceable>s</replaceable>, and <literal>false</literal>
otherwise. This is a dynamic version of the <literal>?</literal>
operator, since <replaceable>s</replaceable> is an expression
rather than an identifier.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.head</function>
<replaceable>list</replaceable></term>
<listitem><para>Return the first element of a list; abort
evaluation if the argument isnt a list or is an empty list. You
can test whether a list is empty by comparing it with
<literal>[]</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>import</function>
<replaceable>path</replaceable></term>
<listitem><para>Load, parse and return the Nix expression in the
file <replaceable>path</replaceable>. Evaluation aborts if the
file doesnt exist or contains an incorrect Nix
expression. <function>import</function> implements Nixs module
system: you can put any Nix expression (such as an attribute set
or a function) in a separate file, and use it from Nix expressions
in other files.</para>
<para>A Nix expression loaded by <function>import</function> must
not contain any <emphasis>free variables</emphasis> (identifiers
that are not defined in the Nix expression itself and are not
built-in). Therefore, it cannot refer to variables that are in
scope at the call site. For instance, if you have a calling
expression
<programlisting>
rec {
x = 123;
y = import ./foo.nix;
}</programlisting>
then the following <filename>foo.nix</filename> will give an
error:
<programlisting>
x + 456</programlisting>
since <varname>x</varname> is not in scope in
<filename>foo.nix</filename>. If you want <varname>x</varname>
to be available in <filename>foo.nix</filename>, you should pass
it as a function argument:
<programlisting>
rec {
x = 123;
y = import ./foo.nix x;
}</programlisting>
and
<programlisting>
x: x + 456</programlisting>
(The function argument doesnt have to be called
<varname>x</varname> in <filename>foo.nix</filename>; any name
would work.)</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to an attribute set, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isList</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a list, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.isFunction</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to a function, and
<literal>false</literal> otherwise.</para></listitem>
</varlistentry>
<varlistentry><term><function>isNull</function>
<replaceable>e</replaceable></term>
<listitem><para>Return <literal>true</literal> if
<replaceable>e</replaceable> evaluates to <literal>null</literal>,
and <literal>false</literal> otherwise.</para>
<warning><para>This function is <emphasis>deprecated</emphasis>;
just write <literal>e == null</literal> instead.</para></warning>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.lessThan</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return <literal>true</literal> if the integer
<replaceable>e1</replaceable> is less than the integer
<replaceable>e2</replaceable>, and <literal>false</literal>
otherwise. Evaluation aborts if either
<replaceable>e1</replaceable> or <replaceable>e2</replaceable>
does not evaluate to an integer.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.listToAttrs</function>
<replaceable>e</replaceable></term>
<listitem><para>Construct an attribute set from a list specifying
the names and values of each attribute. Each element of the list
should be an attribute set consisting of a string-valued attribute
<varname>name</varname> specifying the name of the attribute, and
an attribute <varname>value</varname> specifying its value.
Example:
<programlisting>
builtins.listToAttrs [
{name = "foo"; value = 123;}
{name = "bar"; value = 456;}
]
</programlisting>
evaluates to
<programlisting>
{ foo = 123; bar = 456; }
</programlisting>
</para></listitem>
</varlistentry>
<varlistentry><term><function>map</function>
<replaceable>f</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Apply the function <replaceable>f</replaceable> to
each element in the list <replaceable>list</replaceable>. For
example,
<programlisting>
map (x: "foo" + x) ["bar" "bla" "abc"]</programlisting>
evaluates to <literal>["foobar" "foobla"
"fooabc"]</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.pathExists</function>
<replaceable>path</replaceable></term>
<listitem><para>Return <literal>true</literal> if the path
<replaceable>path</replaceable> exists, and
<literal>false</literal> otherwise. One application of this
function is to conditionally include a Nix expression containing
user configuration:
<programlisting>
let
fileName = builtins.getEnv "CONFIG_FILE";
config =
if fileName != "" &amp;&amp; builtins.pathExists (builtins.toPath fileName)
then import (builtins.toPath fileName)
else { someSetting = false; }; <lineannotation># default configuration</lineannotation>
in config.someSetting</programlisting>
(Note that <envar>CONFIG_FILE</envar> must be an absolute path for
this to work.)</para></listitem>
</varlistentry>
<!--
<varlistentry><term><function>relativise</function></term>
<listitem><para>TODO</para></listitem>
</varlistentry>
-->
<varlistentry><term><function>builtins.readFile</function>
<replaceable>path</replaceable></term>
<listitem><para>Return the contents of the file
<replaceable>path</replaceable> as a string.</para></listitem>
</varlistentry>
<varlistentry><term><function>removeAttrs</function>
<replaceable>attrs</replaceable> <replaceable>list</replaceable></term>
<listitem><para>Remove the attributes listed in
<replaceable>list</replaceable> from the attribute set
<replaceable>attrs</replaceable>. The attributes dont have to
exist in <replaceable>attrs</replaceable>. For instance,
<screen>
removeAttrs { x = 1; y = 2; z = 3; } ["a" "x" "z"]</screen>
evaluates to <literal>{y = 2;}</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.stringLength</function>
<replaceable>e</replaceable></term>
<listitem><para>Return the length of the string
<replaceable>e</replaceable>. If <replaceable>e</replaceable> is
not a string, evaluation is aborted.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.sub</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Return the difference between the integers
<replaceable>e1</replaceable> and
<replaceable>e2</replaceable>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.substring</function>
<replaceable>start</replaceable> <replaceable>len</replaceable>
<replaceable>s</replaceable></term>
<listitem><para>Return the substring of
<replaceable>s</replaceable> from character position
<replaceable>start</replaceable> (zero-based) up to but not
including <replaceable>start + len</replaceable>. If
<replaceable>start</replaceable> is greater than the length of the
string, an empty string is returned, and if <replaceable>start +
len</replaceable> lies beyond the end of the string, only the
substring up to the end of the string is returned.
<replaceable>start</replaceable> must be
non-negative.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.tail</function>
<replaceable>list</replaceable></term>
<listitem><para>Return the second to last elements of a list;
abort evaluation if the argument isnt a list or is an empty
list.</para></listitem>
</varlistentry>
<varlistentry><term><function>throw</function>
<replaceable>s</replaceable></term>
<listitem><para>Throw an error message
<replaceable>s</replaceable>. This usually aborts Nix expression
evaluation, but in <command>nix-env -qa</command> and other
commands that try to evaluate a set of derivations to get
information about those derivations, a derivation that throws an
error is silently skipped (which is not the case for
<function>abort</function>).</para></listitem>
</varlistentry>
<varlistentry
xml:id='builtin-toFile'><term><function>builtins.toFile</function>
<replaceable>name</replaceable> <replaceable>s</replaceable></term>
<listitem><para>Store the string <replaceable>s</replaceable> in a
file in the Nix store and return its path. The file has suffix
<replaceable>name</replaceable>. This file can be used as an
input to derivations. One application is to write builders
“inline”. For instance, the following Nix expression combines
<xref linkend='ex-hello-nix' /> and <xref
linkend='ex-hello-builder' /> into one file:
<programlisting>
{stdenv, fetchurl, perl}:
stdenv.mkDerivation {
name = "hello-2.1.1";
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
PATH=$perl/bin:$PATH
tar xvfz $src
cd hello-*
./configure --prefix=$out
make
make install
";
src = fetchurl {
url = http://nix.cs.uu.nl/dist/tarballs/hello-2.1.1.tar.gz;
md5 = "70c9ccf9fac07f762c24f2df2290784d";
};
inherit perl;
}</programlisting>
</para>
<para>It is even possible for one file to refer to another, e.g.,
<programlisting>
builder = let
configFile = builtins.toFile "foo.conf" "
# This is some dummy configuration file.
<replaceable>...</replaceable>
";
in builtins.toFile "builder.sh" "
source $stdenv/setup
<replaceable>...</replaceable>
cp ${configFile} $out/etc/foo.conf
";</programlisting>
Note that <literal>${configFile}</literal> is an antiquotation
(see <xref linkend='ssec-values' />), so the result of the
expression <literal>configFile</literal> (i.e., a path like
<filename>/nix/store/m7p7jfny445k...-foo.conf</filename>) will be
spliced into the resulting string.</para>
<para>It is however <emphasis>not</emphasis> allowed to have files
mutually referring to each other, like so:
<programlisting>
let
foo = builtins.toFile "foo" "...${bar}...";
bar = builtins.toFile "bar" "...${foo}...";
in foo</programlisting>
This is not allowed because it would cause a cyclic dependency in
the computation of the cryptographic hashes for
<varname>foo</varname> and <varname>bar</varname>.</para></listitem>
</varlistentry>
<varlistentry><term><function>builtins.toPath</function> <replaceable>s</replaceable></term>
<listitem><para>Convert the string value
<replaceable>s</replaceable> into a path value. The string
<replaceable>s</replaceable> must represent an absolute path
(i.e., must start with <literal>/</literal>). The path need not
exist. The resulting path is canonicalised, e.g.,
<literal>builtins.toPath "//foo/xyzzy/../bar/"</literal> returns
<literal>/foo/bar</literal>.</para></listitem>
</varlistentry>
<varlistentry><term><function>toString</function> <replaceable>e</replaceable></term>
<listitem><para>Convert the expression
<replaceable>e</replaceable> to a string.
<replaceable>e</replaceable> can be a string (in which case
<function>toString</function> is a no-op) or a path (e.g.,
<literal>toString /foo/bar</literal> yields
<literal>"/foo/bar"</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id='builtin-toXML'><term><function>builtins.toXML</function> <replaceable>e</replaceable></term>
<listitem><para>Return a string containing an XML representation
of <replaceable>e</replaceable>. The main application for
<function>toXML</function> is to communicate information with the
builder in a more structured format than plain environment
variables.</para>
<!-- TODO: more formally describe the schema of the XML
representation -->
<para><xref linkend='ex-toxml' /> shows an example where this is
the case. The builder is supposed to generate the configuration
file for a <link xlink:href='http://jetty.mortbay.org/'>Jetty
servlet container</link>. A servlet container contains a number
of servlets (<filename>*.war</filename> files) each exported under
a specific URI prefix. So the servlet configuration is a list of
attribute sets containing the <varname>path</varname> and
<varname>war</varname> of the servlet (<xref
linkend='ex-toxml-co-servlets' />). This kind of information is
difficult to communicate with the normal method of passing
information through an environment variable, which just
concatenates everything together into a string (which might just
work in this case, but wouldnt work if fields are optional or
contain lists themselves). Instead the Nix expression is
converted to an XML representation with
<function>toXML</function>, which is unambiguous and can easily be
processed with the appropriate tools. For instance, in the
example an XSLT stylesheet (<xref linkend='ex-toxml-co-stylesheet'
/>) is applied to it (<xref linkend='ex-toxml-co-apply' />) to
generate the XML configuration file for the Jetty server. The XML
representation produced from <xref linkend='ex-toxml-co-servlets'
/> by <function>toXML</function> is shown in <xref
linkend='ex-toxml-result' />.</para>
<para>Note that <xref linkend='ex-toxml' /> uses the <function
linkend='builtin-toFile'>toFile</function> built-in to write the
builder and the stylesheet “inline” in the Nix expression. The
path of the stylesheet is spliced into the builder at
<literal>xsltproc ${stylesheet}
<replaceable>...</replaceable></literal>.</para>
<example xml:id='ex-toxml'><title>Passing information to a builder
using <function>toXML</function></title>
<programlisting><![CDATA[
{stdenv, fetchurl, libxslt, jira, uberwiki}:
stdenv.mkDerivation (rec {
name = "web-server";
buildInputs = [libxslt];
builder = builtins.toFile "builder.sh" "
source $stdenv/setup
mkdir $out
echo $servlets | xsltproc ${stylesheet} - > $out/server-conf.xml]]> <co xml:id='ex-toxml-co-apply' /> <![CDATA[
";
stylesheet = builtins.toFile "stylesheet.xsl"]]> <co xml:id='ex-toxml-co-stylesheet' /> <![CDATA[
"<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform' version='1.0'>
<xsl:template match='/'>
<Configure>
<xsl:for-each select='/expr/list/attrs'>
<Call name='addWebApplication'>
<Arg><xsl:value-of select=\"attr[@name = 'path']/string/@value\" /></Arg>
<Arg><xsl:value-of select=\"attr[@name = 'war']/path/@value\" /></Arg>
</Call>
</xsl:for-each>
</Configure>
</xsl:template>
</xsl:stylesheet>
";
servlets = builtins.toXML []]> <co xml:id='ex-toxml-co-servlets' /> <![CDATA[
{ path = "/bugtracker"; war = jira + "/lib/atlassian-jira.war"; }
{ path = "/wiki"; war = uberwiki + "/uberwiki.war"; }
];
})]]></programlisting>
</example>
<example xml:id='ex-toxml-result'><title>XML representation produced by
<function>toXML</function></title>
<programlisting><![CDATA[<?xml version='1.0' encoding='utf-8'?>
<expr>
<list>
<attrs>
<attr name="path">
<string value="/bugtracker" />
</attr>
<attr name="war">
<path value="/nix/store/d1jh9pasa7k2...-jira/lib/atlassian-jira.war" />
</attr>
</attrs>
<attrs>
<attr name="path">
<string value="/wiki" />
</attr>
<attr name="war">
<path value="/nix/store/y6423b1yi4sx...-uberwiki/uberwiki.war" />
</attr>
</attrs>
</list>
</expr>]]></programlisting>
</example>
</listitem>
</varlistentry>
<varlistentry><term><function>builtins.trace</function>
<replaceable>e1</replaceable> <replaceable>e2</replaceable></term>
<listitem><para>Evaluate <replaceable>e1</replaceable> and print its
abstract syntax representation on standard error. Then return
<replaceable>e2</replaceable>. This function is useful for
debugging.</para></listitem>
</varlistentry>
</variablelist>
</section>

View File

@@ -118,6 +118,123 @@ env-keep-derivations = false
</varlistentry>
<varlistentry xml:id="conf-build-max-silent-time"><term><literal>build-max-silent-time</literal></term>
<listitem>
<para>This option defines the maximum number of seconds that a
builder can go without producing any data on standard output or
standard error. This is useful (for instance in a automated
build system) to catch builds that are stuck in an infinite
loop, or to catch remote builds that are hanging due to network
problems. It can be overriden using the <option
linkend="opt-max-silent-time">--max-silent-time</option> command
line switch.</para>
<para>The value <literal>0</literal> means that there is no
timeout. This is also the default.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-build-users-group"><term><literal>build-users-group</literal></term>
<listitem><para>This options specifies the Unix group containing
the Nix build user accounts. In multi-user Nix installations,
builds should not be performed by the Nix account since that would
allow users to arbitrarily modify the Nix store and database by
supplying specially crafted builders; and they cannot be performed
by the calling user since that would allow him/her to influence
the build result.</para>
<para>Therefore, if this option is non-empty and specifies a valid
group, builds will be performed under the user accounts that are a
member of the group specified here (as listed in
<filename>/etc/group</filename>). Those user accounts should not
be used for any other purpose!</para>
<para>Nix will never run two builds under the same user account at
the same time. This is to prevent an obvious security hole: a
malicious user writing a Nix expression that modifies the build
result of a legitimate Nix expression being built by another user.
Therefore it is good to have as many Nix build user accounts as
you can spare. (Remember: uids are cheap.)</para>
<para>The build users should have permission to create files in
the Nix store, but not delete them. Therefore,
<filename>/nix/store</filename> should be owned by the Nix
account, its group should be the group specified here, and its
mode should be <literal>1775</literal>.</para>
<para>If the build users group is empty, builds will be performed
under the uid of the Nix process (that is, the uid of the caller
if <envar>NIX_REMOTE</envar> is empty, the uid under which the Nix
daemon runs if <envar>NIX_REMOTE</envar> is
<literal>daemon</literal>, or the uid that owns the setuid
<command>nix-worker</command> program if <envar>NIX_REMOTE</envar>
is <literal>slave</literal>). Obviously, this should not be used
in multi-user settings with untrusted users.</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>build-use-chroot</literal></term>
<listitem><para>If set to <literal>true</literal>, builds will be
performed in a <emphasis>chroot environment</emphasis>, i.e., the
build will be isolated from the normal file system hierarchy and
will only see the Nix store, the temporary build directory, and
the directories configured with the <link
linkend='conf-build-chroot-dirs'><literal>build-chroot-dirs</literal>
option</link> (such as <filename>/proc</filename> and
<filename>/dev</filename>). This is useful to prevent undeclared
dependencies on files in directories such as
<filename>/usr/bin</filename>.</para>
<para>The use of a chroot requires that Nix is run as root (but
you can still use the <link
linkend='conf-build-users-group'>“build users” feature</link> to
perform builds under different users than root). Currently,
chroot builds only work on Linux because Nix uses “bind mounts” to
make the Nix store and other directories available inside the
chroot.</para>
</listitem>
</varlistentry>
<varlistentry xml:id="conf-build-chroot-dirs"><term><literal>build-chroot-dirs</literal></term>
<listitem><para>When builds are performed in a chroot environment,
Nix will mount (using <command>mount --bind</command> on Linux)
some directories from the normal file system hierarchy inside the
chroot. These are the Nix store, the temporary build directory
(usually
<filename>/tmp/nix-<replaceable>pid</replaceable>-<replaceable>number</replaceable></filename>)
and the directories listed here. The default is <literal>dev
/proc</literal>. Files in <filename>/dev</filename> (such as
<filename>/dev/null</filename>) are needed by many builds, and
some files in <filename>/proc</filename> may also be needed
occasionally.</para>
<para>The value used on NixOS is
<programlisting>
build-use-chroot = /dev /proc /bin</programlisting>
to make the <filename>/bin/sh</filename> symlink available (which
is still needed by many builders).</para>
</listitem>
</varlistentry>
<varlistentry><term><literal>system</literal></term>
<listitem><para>This option specifies the canonical Nix system

View File

@@ -10,17 +10,6 @@
<variablelist>
<varlistentry><term><envar>NIX_ROOT</envar></term>
<listitem><para>If <envar>NIX_ROOT</envar> is set, the Nix command
will on startup perform a <function>chroot()</function> to the
specified directory. This is useful in certain bootstrapping
situations (e.g., when installing a Nix installation onto a hard
disk from CD-ROM).</para></listitem>
</varlistentry>
<varlistentry><term><envar>NIX_IGNORE_SYMLINK_STORE</envar></term>
<listitem>
@@ -274,6 +263,17 @@ $ mount -o bind /mnt/otherdisk/nix /nix</screen>
</varlistentry>
<varlistentry xml:id="envar-remote"><term><envar>NIX_REMOTE</envar></term>
<listitem><para>This variable should be set to
<literal>daemon</literal> if you want to use the Nix daemon to
executed Nix operations, which is necessary in <link
linkend="ssec-multi-user">multi-user Nix installations</link>.
Otherwise, it should be left unset.</para></listitem>
</varlistentry>
</variablelist>

View File

@@ -74,9 +74,9 @@
<glossentry><glossterm>Nix expression</glossterm>
<glossdef><para>A high-level description of software components and
<glossdef><para>A high-level description of software packages and
compositions thereof. Deploying software using Nix entails writing
Nix expressions for your components. Nix expressions are translated
Nix expressions for your packages. Nix expressions are translated
to derivations that are stored in the Nix store. These derivations
can then be built.</para></glossdef>

View File

@@ -6,12 +6,44 @@
<title>Installation</title>
<section><title>Supported platforms</title>
<para>Nix is currently supported on the following platforms:
<itemizedlist>
<listitem><para>Linux (particularly on x86, x86_64, and
PowerPC).</para></listitem>
<listitem><para>Mac OS X, both on Intel and
PowerPC.</para></listitem>
<listitem><para>FreeBSD (only tested on Intel).</para></listitem>
<listitem><para>Windows through <link
xlink:href="http://www.cygwin.com/">Cygwin</link>.</para>
<warning><para>On Cygwin, Nix <emphasis>must</emphasis> be installed
on an NTFS partition. It will not work correctly on a FAT
partition.</para></warning>
</listitem>
</itemizedlist>
</para>
<para>Nix is pretty portable, so it should work on most other Unix
platforms as well.</para>
</section>
<section><title>Obtaining Nix</title>
<para>The easiest way to obtain Nix is to download a <link
xlink:href="http://www.cs.uu.nl/groups/ST/Trace/Nix">source
distribution</link>. RPMs for Red Hat, SuSE, and Fedora Core are also
available.</para>
xlink:href="http://nix.cs.uu.nl/">source distribution</link>. RPMs
for Red Hat, SuSE, and Fedora Core are also available.</para>
<para>Alternatively, the most recent sources of Nix can be obtained
from its <link
@@ -57,25 +89,28 @@ repository.</para>
<para>To build the parser, very <emphasis>recent</emphasis> versions
of Bison and Flex are required. (This is because Nix needs GLR
support in Bison and reentrancy support in Flex.) For Bison, you need
version 1.875c or higher (1.875 does <emphasis>not</emphasis> work),
which can be obtained from the <link
xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP server</link>.
For Flex, you need version 2.5.31, which is available on <link
xlink:href="http://lex.sourceforge.net/">SourceForge</link>. Slightly
older versions may also work, but ancient versions like the ubiquitous
2.5.4a won't. Note that these are only required if you modify the
parser or when you are building from the Subversion repository.</para>
version 2.3 or higher (1.875 does <emphasis>not</emphasis> work),
which can be obtained from
the <link xlink:href="ftp://alpha.gnu.org/pub/gnu/bison">GNU FTP
server</link>. For Flex, you need version 2.5.33, which is available
on <link xlink:href="http://lex.sourceforge.net/">SourceForge</link>.
Slightly older versions may also work, but ancient versions like the
ubiquitous 2.5.4a won't. Note that these are only required if you
modify the parser or when you are building from the Subversion
repository.</para>
<para>Nix uses Sleepycat's Berkeley DB and CWI's ATerm library. These
are included in the Nix source distribution. If you build from the
Subversion repository, you must download them yourself and place them
in the <filename>externals/</filename> directory. See
<para>Nix uses Sleepycat's Berkeley DB, CWI's ATerm library and the
bzip2 compressor (including the bzip2 library). These are included in
the Nix source distribution. If you build from the Subversion
repository, you must download them yourself and place them in the
<filename>externals/</filename> directory. See
<filename>externals/Makefile.am</filename> for the precise URLs of
these packages. Alternatively, if you already have them installed,
you can use <command>configure</command>'s <option>--with-bdb</option>
and <option>--with-aterm</option> options to point to their respective
you can use <command>configure</command>'s
<option>--with-bdb</option>, <option>--with-aterm</option> and
<option>--with-bzip2</option> options to point to their respective
locations. Note that Berkeley DB <emphasis>must</emphasis> be version
4.4; other versions may not have compatible database formats.</para>
4.5; other versions may not have compatible database formats.</para>
</section>
@@ -84,19 +119,21 @@ locations. Note that Berkeley DB <emphasis>must</emphasis> be version
<para>After unpacking or checking out the Nix sources, issue the
following commands:
</para>
<screen>
$ ./configure <replaceable>options...</replaceable>
$ make
$ make install</screen>
</para>
<para>When building from the Subversion repository, these should be
preceded by the command:
</para>
<screen>
$ autoreconf -i</screen>
$ ./bootstrap</screen>
</para>
<para>The installation path can be specified by passing the
<option>--prefix=<replaceable>prefix</replaceable></option> to
@@ -123,28 +160,32 @@ options.</para>
<section><title>Installing from RPMs</title>
<para>RPM packages of Nix can be downloaded from <uri
xlink:href="http://www.cs.uu.nl/groups/ST/Trace/Nix">http://www.cs.uu.nl/groups/ST/Trace/Nix</uri>.
These RPMs should work for most fairly recent releases of SuSE and Red
Hat Linux. They have been known to work work on SuSE Linux 8.1 and
9.0, and Red Hat 9.0. In fact, it should work on any RPM-based Linux
distribution based on <literal>glibc</literal> 2.3 or later.</para>
<para>RPM packages of Nix can be downloaded from <link
xlink:href="http://nix.cs.uu.nl/" />. These RPMs should work for most
fairly recent releases of SuSE and Red Hat Linux. They have been
known to work work on SuSE Linux 8.1 and 9.0, and Red Hat 9.0. In
fact, it should work on any RPM-based Linux distribution based on
<literal>glibc</literal> 2.3 or later.</para>
<para>Once downloaded, the RPMs can be installed or upgraded using
<command>rpm -U</command>. For example,</para>
<command>rpm -U</command>. For example,
<screen>
$ rpm -U nix-0.5pre664-1.i386.rpm</screen>
</para>
<para>The RPMs install into the directory <filename>/nix</filename>.
Nix can be uninstalled using <command>rpm -e nix</command>. After
this it will be necessary to manually remove the Nix store and other
auxiliary data:</para>
auxiliary data:
<screen>
$ rm -rf /nix/store
$ rm -rf /nix/var</screen>
</para>
</section>
@@ -152,8 +193,8 @@ $ rm -rf /nix/var</screen>
<para>You can install the latest stable version of Nix through Nix
itself by subscribing to the channel <link
xlink:href="http://nix.cs.uu.nl/dist/nix/channels-v3/nix-stable" /> ,
or the latest unstable version by subscribing to the channel<link
xlink:href="http://nix.cs.uu.nl/dist/nix/channels-v3/nix-stable" />,
or the latest unstable version by subscribing to the channel <link
xlink:href="http://nix.cs.uu.nl/dist/nix/channels-v3/nix-unstable" />.
You can also do a <link linkend="sec-one-click">one-click
installation</link> by clicking on the package links at <link
@@ -162,54 +203,252 @@ xlink:href="http://nix.cs.uu.nl/dist/nix/" />.</para>
</section>
<section><title>Permissions</title>
<section><title>Security</title>
<para>All Nix operations must be performed under the user ID that owns
the Nix store and database
(<filename><replaceable>prefix</replaceable>/store</filename> and
<filename><replaceable>prefix</replaceable>/var/nix/db</filename>,
respectively). When installed from the RPM packages, these
directories are owned by <systemitem class="username">root</systemitem>.</para>
<para>Nix has two basic security models. First, it can be used in
“single-user mode”, which is similar to what most other package
management tools do: there is a single user (typically <systemitem
class="username">root</systemitem>) who performs all package
management operations. All other users can then use the installed
packages, but they cannot perform package management operations
themselves.</para>
<section><title>Setuid installation</title>
<para>Alternatively, you can configure Nix in “multi-user mode”. In
this model, all users can perform package management operations — for
instance, every user can install software without requiring root
privileges. Nix ensures that this is secure. For instance, its not
possible for one user to overwrite a package used by another user with
a Trojan horse.</para>
<para>As a somewhat <emphasis>ad hoc</emphasis> hack, you can also
install the Nix binaries <quote>setuid</quote> so that a Nix store can
be shared among several users. To do this, configure Nix with the
<emphasis>--enable-setuid</emphasis> option. Nix will be installed as
owned by a user and group specified by the
<option>--with-nix-user=</option><parameter>user</parameter> and
<option>--with-nix-group=</option><parameter>group</parameter>
options. E.g.,
<screen>
$ ./configure --enable-setuid --with-nix-user=my_nix_user --with-nix-group=my_nix_group</screen>
<section><title>Single-user mode</title>
<para>In single-user mode, all Nix operations that access the database
in <filename><replaceable>prefix</replaceable>/var/nix/db</filename>
or modify the Nix store in
<filename><replaceable>prefix</replaceable>/store</filename> must be
performed under the user ID that owns those directories. This is
typically <systemitem class="username">root</systemitem>. (If you
install from RPM packages, thats in fact the default ownership.)
However, on single-user machines, it is often convenient to
<command>chown</command> those directories to your normal user account
so that you dont have to <command>su</command> to <systemitem
class="username">root</systemitem> all the time.</para>
The user and group default to <literal>nix</literal>. You should make
sure that both the user and the group exist. Any <quote>real</quote>
users that you want to allow access should be added to the Nix
</section>
<section xml:id="ssec-multi-user"><title>Multi-user mode</title>
<para>To allow a Nix store to be shared safely among multiple users,
it is important that users are not able to run builders that modify
the Nix store or database in arbitrary ways, or that interfere with
builds started by other users. If they could do so, they could
install a Trojan horse in some package and compromise the accounts of
other users.</para>
<para>To prevent this, the Nix store and database are owned by some
privileged user (usually <literal>root</literal>) and builders are
executed under special user accounts (usually named
<literal>nixbld1</literal>, <literal>nixbld2</literal>, etc.). When a
unprivileged user runs a Nix command, actions that operate on the Nix
store (such as builds) are forwarded to a <emphasis>Nix
daemon</emphasis> running under the owner of the Nix store/database
that performs the operation.</para>
<note><para>Multi-user mode has one important limitation: only
<systemitem class="username">root</systemitem> can run <command
linkend="sec-nix-pull">nix-pull</command> to register the availability
of pre-built binaries. However, those registrations are shared by all
users, so they still get the benefit from <command>nix-pull</command>s
done by <systemitem class="username">root</systemitem>.</para></note>
<section><title>Setting up the build users</title>
<para>The <emphasis>build users</emphasis> are the special UIDs under
which builds are performed. They should all be members of the
<emphasis>build users group</emphasis> (usually called
<literal>nixbld</literal>). This group should have no other members.
The build users should not be members of any other group.</para>
<para>Here is a typical <filename>/etc/group</filename> definition of
the build users group with 10 build users:
<programlisting>
nixbld:!:30000:nixbld1,nixbld2,nixbld3,nixbld4,nixbld5,nixbld6,nixbld7,nixbld8,nixbld9,nixbld10
</programlisting>
In this example the <literal>nixbld</literal> group has UID 30000, but
of course it can be anything that doesnt collide with an existing
group.</para>
<warning><para>A setuid installation should only by used if the users
in the Nix group are mutually trusted, since any user in that group
has the ability to change anything in the Nix store or database. For
instance, they could install a trojan horse in executables used by
other users.</para></warning>
<para>Here is the corresponding part of
<filename>/etc/passwd</filename>:
<warning><para>On some platforms, the Nix binaries will be installed
as setuid <literal>root</literal>. They drop root privileges
immediately after startup and switch to the Nix user. The reason for
this is that both the real and effective user must be set to the Nix
user, and POSIX has no system call to do this. This is not the case
on systems that have the <function>setresuid()</function> system call
(such as Linux and FreeBSD), so on those systems the binaries are
simply owned by the Nix user.</para></warning>
<programlisting>
nixbld1:x:30001:65534:Nix build user 1:/var/empty:/noshell
nixbld2:x:30002:65534:Nix build user 2:/var/empty:/noshell
nixbld3:x:30003:65534:Nix build user 3:/var/empty:/noshell
...
nixbld10:x:30010:65534:Nix build user 10:/var/empty:/noshell
</programlisting>
The home directory of the build users should not exist or should be an
empty directory to which they do not have write access.</para>
<para>The build users should have write access to the Nix store, but
they should not have the right to delete files. Thus the Nix stores
group should be the build users group, and it should have the sticky
bit turned on (like <filename>/tmp</filename>):
<screen>
$ chgrp nixbld /nix/store
$ chmod 1777 /nix/store
</screen>
</para>
<para>Finally, you should tell Nix to use the build users by
specifying the build users group in the <link
linkend="conf-build-users-group"><literal>build-users-group</literal>
option</link> in the <link linkend="sec-conf-file">Nix configuration
file</link> (<literal>/nix/etc/nix/nix.conf</literal>):
<programlisting>
build-users-group = nixbld
</programlisting>
</para>
</section>
<section><title>Nix store/database owned by root</title>
<para>The simplest setup is to let <literal>root</literal> own the Nix
store and database. I.e.,
<screen>
$ chown -R root /nix/store /nix/var/nix</screen>
</para>
<para>The Nix daemon should be started as follows (as
<literal>root</literal>):
<screen>
$ nix-worker --daemon</screen>
Youll want to put that line somewhere in your systems boot
scripts.</para>
<para>To let unprivileged users use the daemon, they should set the
<link linkend="envar-remote"><envar>NIX_REMOTE</envar> environment
variable</link> to <literal>daemon</literal>. So you should put a
line like
<programlisting>
export NIX_REMOTE=daemon</programlisting>
into the users login scripts.</para>
</section>
<section><title>Nix store/database not owned by root</title>
<para>It is also possible to let the Nix store and database be owned
by a non-root user, which should be more secure<footnote><para>Note
however that even when the Nix daemon runs as root, not
<emphasis>that</emphasis> much code is executed as root: Nix
expression evaluation is performed by the calling (unprivileged) user,
and builds are performed under the special build user accounts. So
only the code that accesses the database and starts builds is executed
as <literal>root</literal>.</para></footnote>. Typically, this user
is a special account called <literal>nix</literal>, but it can be
named anything. It should own the Nix store and database:
<screen>
$ chown -R root /nix/store /nix/var/nix</screen>
and of course <command>nix-worker --daemon</command> should be started
under that user, e.g.,
<screen>
$ su - nix -c "exec /nix/bin/nix-worker --daemon"</screen>
</para>
<para>There is a catch, though: non-<literal>root</literal> users
cannot start builds under the build user accounts, since the
<function>setuid</function> system call is obviously privileged. To
allow a non-<literal>root</literal> Nix daemon to use the build user
feature, it calls a setuid-root helper program,
<command>nix-setuid-helper</command>. This program is installed in
<filename><replaceable>prefix</replaceable>/libexec/nix-setuid-helper</filename>.
To set the permissions properly (Nixs <command>make install</command>
doesnt do this, since we dont want to ship setuid-root programs
out-of-the-box):
<screen>
$ chown root.root /nix/libexec/nix-setuid-helper
$ chmod 4755 /nix/libexec/nix-setuid-helper
</screen>
(This example assumes that the Nix binaries are installed in
<filename>/nix</filename>.)</para>
<para>Of course, the <command>nix-setuid-helper</command> command
should not be usable by just anybody, since then anybody could run
commands under the Nix build user accounts. For that reason there is
a configuration file <filename>/etc/nix-setuid.conf</filename> that
restricts the use of the helper. This file should be a text file
containing precisely two lines, the first being the Nix daemon user
and the second being the build users group, e.g.,
<programlisting>
nix
nixbld
</programlisting>
The setuid-helper barfs if it is called by a user other than the one
specified on the first line, or if it is asked to execute a build
under a user who is not a member of the group specified on the second
line. The file <filename>/etc/nix-setuid.conf</filename> must be
owned by root, and must not be group- or world-writable. The
setuid-helper barfs if this is not the case.</para>
</section>
<section><title>Restricting access</title>
<para>To limit which users can perform Nix operations, you can use the
permissions on the directory
<filename>/nix/var/nix/daemon-socket</filename>. For instance, if you
want to restrict the use of Nix to the members of a group called
<literal>nix-users</literal>, do
<screen>
$ chgrp nix-users /nix/var/nix/daemon-socket
$ chmod ug=rwx,o= /nix/var/nix/daemon-socket
</screen>
This way, users who are not in the <literal>nix-users</literal> group
cannot connect to the Unix domain socket
<filename>/nix/var/nix/daemon-socket/socket</filename>, so they cannot
perform Nix operations.</para>
</section>
</section> <!-- end of multi-user -->
</section> <!-- end of security -->
<section><title>Using Nix</title>
<para>To use Nix, some environment variables should be set. In

View File

@@ -1,135 +1,304 @@
<chapter xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="chap-introduction">
<title>Introduction</title>
<para>Nix is a system for the deployment of software. Software
deployment is concerned with the creation, distribution, and
management of software components (<quote>packages</quote>). Its main
features are:
<itemizedlist>
<section><title>About Nix</title>
<listitem><para>It helps you make sure that dependency specifications
are complete. In general in a deployment system you have to specify
for each component what its dependencies are, but there are no
guarantees that this specification is complete. If you forget a
dependency, then the component will build and work correctly on
<emphasis>your</emphasis> machine if you have the dependency
installed, but not on the end user's machine if it's not
there.</para></listitem>
<para>Nix is a <emphasis>purely functional package manager</emphasis>.
This means that it treats packages like values in purely functional
programming languages such as Haskell — they are built by functions
that dont have side-effects, and they never change after they have
been built. Nix stores packages in the <emphasis>Nix
store</emphasis>, usually the directory
<filename>/nix/store</filename>, where each package has its own unique
subdirectory such as
<listitem><para>It is possible to have <emphasis>multiple versions or
variants</emphasis> of a component installed at the same time. In
contrast, in systems such as RPM different versions of the same
package tend to install to the same location in the file system, so
installing one version will remove the other. This is especially
important if you want to use applications that have conflicting
requirements on different versions of a component (e.g., application A
requires version 1.0 of library X, while application B requires a
non-backwards compatible version 1.1).</para></listitem>
<programlisting>
/nix/store/r8vvq9kq18pz08v249h8my6r9vs7s0n3-firefox-2.0.0.1/
</programlisting>
<listitem><para>Users can have different <quote>views</quote>
(<quote>profiles</quote> in Nix parlance) on the set of installed
applications in a system. For instance, one user can have version 1.0
of some package visible, while another is using version 1.1, and a
third doesn't use it at all.</para></listitem>
where <literal>r8vvq9kq…</literal> is a unique identifier for the
package that captures all its dependencies (its a cryptographic hash
of the packages build dependency graph). This enables many powerful
features.</para>
<listitem><para>It is possible to atomically
<emphasis>upgrade</emphasis> software. I.e., there is no time window
during an upgrade in which part of the old version and part of the new
version are simultaneously visible (which might well cause the
component to fail).</para></listitem>
<listitem><para>Likewise, it is possible to atomically roll back after
an install, upgrade, or uninstall action. That is, in a fast (O(1))
operation the previous configuration of the system can be restored.
This is because upgrade or uninstall actions don't actually remove
components from the system.</para></listitem>
<simplesect><title>Multiple versions</title>
<listitem><para>Unused components can be
<emphasis>garbage-collected</emphasis> automatically and safely: when
you remove an application from a profile, its dependencies will be
deleted by the garbage collector only if there are no other active
applications using them.</para></listitem>
<para>You can have multiple versions or variants of a package
installed at the same time. This is especially important when
different applications have dependencies on different versions of the
same package — it prevents the “DLL hell”. Because of the hashing
scheme, different versions of a package end up in different paths in
the Nix store, so they dont interfere with each other.</para>
<listitem><para>Nix supports both source-based deployment models
(where you distribute <emphasis>Nix expressions</emphasis> that tell
Nix how to build software from source) and binary-based deployment
models. The latter is more-or-less transparent: installation of
components is always based on Nix expressions, but if the expressions
have been built before and Nix knows that the resulting binaries are
available somewhere, it will use those instead.</para></listitem>
<para>An important consequence is that operations like upgrading or
uninstalling an application cannot break other applications, since
these operations never “destructively” update or delete files that are
used by other packages.</para>
<listitem><para>Nix is flexible in the deployment policies that it
supports. There is a clear separation between the tools that
implement basic Nix <emphasis>mechanisms</emphasis> (e.g., building
Nix expressions), and the tools that implement various deployment
<emphasis>policies</emphasis>. For instance, there is a concept of
<quote>Nix channels</quote> that can be used to keep software
installations up-to-date automatically from a network source. This is
a policy that is implemented by a fairly short Perl script, which can
be adapted easily to achieve similar policies.</para></listitem>
</simplesect>
<listitem><para>Nix component builds aim to be <quote>pure</quote>;
that is, unaffected by anything other than the declared dependencies.
This means that if a component was built successfully once, it can be
rebuilt again on another machine and the result will be the same. We
cannot <emphasis>guarantee</emphasis> this (e.g., if the build depends
on the time-of-day), but Nix (and the tools in the Nix Packages
collection) takes special care to help achieve this.</para></listitem>
<listitem><para>Nix expressions (the things that tell Nix how to build
components) are self-contained: they describe not just components but
complete compositions. In other words, Nix expressions also describe
how to build all the dependencies. This is in contrast to component
specification languages like RPM spec files, which might say that a
component X depends on some other component Y, but since it does not
describe <emphasis>exactly</emphasis> what Y is, the result of
building or running X might be different on different machines.
Combined with purity, self-containedness ensures that a component that
<quote>works</quote> on one machine also works on another, when
deployed using Nix.</para></listitem>
<simplesect><title>Complete dependencies</title>
<listitem><para>The Nix expression language makes it easy to describe
variability in components (e.g., optional features or
dependencies).</para></listitem>
<para>Nix helps you make sure that package dependency specifications
are complete. In general, when youre making a package for a package
management system like RPM, you have to specify for each package what
its dependencies are, but there are no guarantees that this
specification is complete. If you forget a dependency, then the
package will build and work correctly on <emphasis>your</emphasis>
machine if you have the dependency installed, but not on the end
user's machine if it's not there.</para>
<listitem><para>Nix is ideal for building build farms that do
continuous builds of software from a version management system, since
it can take care of building all the dependencies as well. Also, Nix
only rebuilds components that have changed, so there are no
unnecessary builds. In addition, Nix can transparently distribute
build jobs over different machines, including different
platforms.</para></listitem>
<para>Since Nix on the other hand doesnt install packages in “global”
locations like <filename>/usr/bin</filename> but in package-specific
directories, the risk of incomplete dependencies is greatly reduced.
This is because tools such as compilers dont search in per-packages
directories such as
<filename>/nix/store/5lbfaxb722zp…-openssl-0.9.8d/include</filename>,
so if a package builds correctly on your system, this is because you
specified the dependency explicitly.</para>
<listitem><para>Nix can be used not only for software deployment, but
also for <emphasis>service deployment</emphasis>, such as the
deployment of a complete web server with all its configuration files,
static pages, software dependencies, and so on. Nix's advantages for
software deployment also apply here: for instance, the ability
trivially to have multiple configurations at the same time, or the
ability to do rollbacks.</para></listitem>
<para>Runtime dependencies are found by scanning binaries for the hash
parts of Nix store paths (such as <literal>r8vvq9kq…</literal>). This
sounds risky, but it works extremely well.</para>
<listitem><para>Nix can efficiently upgrade between different versions
of a component through <emphasis>binary patching</emphasis>. If
patches are available on a server, and you try to install a new
version of some component, Nix will automatically apply a patch (or
sequence of patches), if available, to transform the installed
component into the new version.</para></listitem>
</simplesect>
</itemizedlist>
</para>
<simplesect><title>Multi-user support</title>
<para>Starting at version 0.11, Nix has multi-user support. This
means that non-privileged users can securely install software. Each
user can have a different <emphasis>profile</emphasis>, a set of
packages in the Nix store that appear in the users
<envar>PATH</envar>. If a user installs a package that another user
has already installed previously, the package wont be built or
downloaded a second time. At the same time, it is not possible for
one user to inject a Trojan horse into a package that might be used by
another user.</para>
<!--
<para>More details can be found in Section 3 of our <a
href="docs/papers.html#securesharing">ASE 2005 paper</a>.</para>
-->
</simplesect>
<simplesect><title>Atomic upgrades and rollbacks</title>
<para>Since package management operations never overwrite packages in
the Nix store but just add new versions in different paths, they are
<emphasis>atomic</emphasis>. So during a package upgrade, there is no
time window in which the package has some files from the old version
and some files from the new version — which would be bad because a
program might well crash if its started during that period.</para>
<para>And since package arent overwritten, the old versions are still
there after an upgrade. This means that you can <emphasis>roll
back</emphasis> to the old version:</para>
<screen>
$ nix-env --upgrade <replaceable>some-packages</replaceable>
$ nix-env --rollback
</screen>
</simplesect>
<simplesect><title>Garbage collection</title>
<para>When you install a package like this…
<screen>
$ nix-env --uninstall firefox
</screen>
the package isnt deleted from the system right away (after all, you
might want to do a rollback, or it might be in the profiles of other
users). Instead, unused packages can be deleted safely by running the
<emphasis>garbage collector</emphasis>:
<screen>
$ nix-collect-garbage
</screen>
This deletes all packages that arent in use by any user profile or by
a currently running program.</para>
</simplesect>
<simplesect><title>Functional package language</title>
<para>Packages are built from <emphasis>Nix expressions</emphasis>,
which is a simple functional language. A Nix expression describes
everything that goes into a package build action (a “derivation”):
other packages, sources, the build script, environment variables for
the build script, etc. Nix tries very hard to ensure that Nix
expressions are <emphasis>deterministic</emphasis>: building a Nix
expression twice should yield the same result.</para>
<para>Because its a functional language, its easy to support
building variants of a package: turn the Nix expression into a
function and call it any number of times with the appropriate
arguments. Due to the hashing scheme, variants dont conflict with
each other in the Nix store.</para>
</simplesect>
<simplesect><title>Transparent source/binary deployment</title>
<para>Nix expressions generally describe how to build a package from
source, so an installation action like
<screen>
$ nix-env --install firefox
</screen>
<emphasis>could</emphasis> cause quite a bit of build activity, as not
only Firefox but also all its dependencies (all the way up to the C
library and the compiler) would have to built, at least if they are
not already in the Nix store. This is a <emphasis>source deployment
model</emphasis>. For most users, building from source is not very
pleasant as it takes far too long. However, Nix can automatically
skip building from source and download a pre-built binary instead if
it knows about it. <emphasis>Nix channels</emphasis> provide Nix
expressions along with pre-built binaries.</para>
<!--
<para>source deployment model (like <a
href="http://www.gentoo.org/">Gentoo</a>) and a binary model (like
RPM)</para>
-->
</simplesect>
<simplesect><title>Binary patching</title>
<para>In addition to downloading binaries automatically if theyre
available, Nix can download binary deltas that patch an existing
package in the Nix store into a new version. This speeds up
upgrades.</para>
</simplesect>
<simplesect><title>Nix Packages collection</title>
<para>We provide a large set of Nix expressions containing hundreds of
existing Unix packages, the <emphasis>Nix Packages
collection</emphasis> (Nixpkgs).</para>
</simplesect>
<simplesect><title>Service deployment</title>
<para>Nix can be used not only for rolling out packages, but also
complete <emphasis>configurations</emphasis> of services. This is
done by treating all the static bits of a service (such as software
packages, configuration files, control scripts, static web pages,
etc.) as “packages” that can be built by Nix expressions. As a
result, all the features above apply to services as well: for
instance, you can roll back a web server configuration if a
configuration change turns out to be undesirable, you can easily have
multiple instances of a service (e.g., a test and production server),
and because the whole service is built in a purely functional way from
a Nix expression, it is repeatable so you can easily reproduce the
service on another machine.</para>
<!--
<para>You can read more about this in our <a
href="docs/papers.html#servicecm">SCM-12 paper</a>.</para>
-->
</simplesect>
<simplesect><title>Portability</title>
<para>Nix should run on most Unix systems, including Linux, FreeBSD and
Mac OS X. It is also supported on Windows using Cygwin.</para>
</simplesect>
<simplesect><title>NixOS</title>
<para>NixOS is a Linux distribution based on Nix. It uses Nix not
just for package management but also to manage the system
configuration (e.g., to build configuration files in
<filename>/etc</filename>). This means, among other things, that its
possible to easily roll back the entire configuration of the system to
an earlier state. Also, users can install software without root
privileges. For more information and downloads, see the <link
xlink:href="http://nix.cs.uu.nl/nixos/">NixOS homepage</link>.</para>
</simplesect>
<!-- other features:
- build farms
- reproducibility (Nix expressions allows whole configuration to be rebuilt)
-->
</section>
<section><title>About us</title>
<para>Nix was developed at the <link
xlink:href="http://www.cs.uu.nl/">Department of Information and
Computing Sciences</link>, Utrecht University by the <link
xlink:href="http://www.cs.uu.nl/wiki/Trace/WebHome">TraCE
project</link>. The project is funded by the Software Engineering
Research Program <link
xlink:href="http://www.jacquard.nl/">Jacquard</link> to improve the
support for variability in software systems.</para>
</section>
<section><title>About this manual</title>
<para>This manual tells you how to install and use Nix and how to
write Nix expressions for software not already in the Nix Packages
collection. It also discusses some advanced topics, such as setting
up a Nix-based build farm, and doing service deployment using
Nix.</para>
up a Nix-based build farm.</para>
<note><para>Some background information on Nix can be found in a
number of papers. The ICSE 2004 paper <citetitle
</section>
<section><title>License</title>
<para>Nix is free software; you can redistribute it and/or modify it
under the terms of the <link
xlink:href="http://www.gnu.org/licenses/lgpl.html">GNU Lesser General
Public License</link> as published by the <link
xlink:href="http://www.fsf.org/">Free Software Foundation</link>;
either version 2.1 of the License, or (at your option) any later
version. Nix is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.</para>
</section>
<section><title>More information</title>
<para>Some background information on Nix can be found in a number of
papers. The ICSE 2004 paper <citetitle
xlink:href='http://www.cs.uu.nl/~eelco/pubs/immdsd-icse2004-final.pdf'>Imposing
a Memory Management Discipline on Software Deployment</citetitle>
discusses the hashing mechanism used to ensure reliable dependency
@@ -141,10 +310,27 @@ gives a more general discussion of Nix from a system-administration
perspective. The CBSE 2005 paper <citetitle
xlink:href='http://www.cs.uu.nl/~eelco/pubs/eupfcdm-cbse2005-final.pdf'>Efficient
Upgrading in a Purely Functional Component Deployment Model
</citetitle> is about transparent patch deployment in Nix. Finally,
the SCM-12 paper <citetitle
</citetitle> is about transparent patch deployment in Nix. The SCM-12
paper <citetitle
xlink:href='http://www.cs.uu.nl/~eelco/pubs/servicecm-scm12-final.pdf'>
Service Configuration Management</citetitle> shows how services (e.g.,
web servers) can be deployed and managed through Nix.</para></note>
web servers) can be deployed and managed through Nix. A short
overview of NixOS is given in the HotOS XI paper <citetitle
xlink:href="http://www.cs.uu.nl/~eelco/pubs/hotos-final.pdf">Purely
Functional System Configuration Management</citetitle>. The Nix
homepage has <link
xlink:href="http://nix.cs.uu.nl/docs/papers.html">an up-to-date list
of Nix-related papers</link>.</para>
<para>Nix is the subject of Eelco Dolstras PhD thesis <citetitle
xlink:href="http://igitur-archive.library.uu.nl/dissertations/2006-0118-200031/index.htm">The
Purely Functional Software Deployment Model</citetitle>, which
contains most of the papers listed above.</para>
<para>Nix has a homepage at <link
xlink:href="http://nix.cs.uu.nl/"/>.</para>
</section>
</chapter>

View File

@@ -13,14 +13,21 @@
<firstname>Eelco</firstname>
<surname>Dolstra</surname>
</personname>
<affiliation>
<orgname>Utrecht University</orgname>
<orgdiv>Faculty of Science, Department of Information and Computing Sciences</orgdiv>
</affiliation>
</author>
<copyright>
<year>2004</year>
<year>2005</year>
<year>2006</year>
<year>2007</year>
<holder>Eelco Dolstra</holder>
</copyright>
<date>September 2007</date>
</info>
@@ -49,7 +56,7 @@
<title>nix-instantiate</title>
<xi:include href="nix-instantiate.xml" />
</section>
<section>
<section xml:id="sec-nix-store">
<title>nix-store</title>
<xi:include href="nix-store.xml" />
</section>
@@ -65,10 +72,14 @@
<title>nix-channel</title>
<xi:include href="nix-channel.xml" />
</section>
<section>
<section xml:id="sec-nix-collect-garbage">
<title>nix-collect-garbage</title>
<xi:include href="nix-collect-garbage.xml" />
</section>
<section xml:id="sec-nix-copy-closure">
<title>nix-copy-closure</title>
<xi:include href="nix-copy-closure.xml" />
</section>
<section xml:id="sec-nix-hash">
<title>nix-hash</title>
<xi:include href="nix-hash.xml" />
@@ -77,15 +88,15 @@
<title>nix-install-package</title>
<xi:include href="nix-install-package.xml" />
</section>
<section>
<section xml:id="sec-nix-pack-closure">
<title>nix-pack-closure</title>
<xi:include href="nix-pack-closure.xml" />
</section>
<section>
<section xml:id="sec-nix-prefetch-url">
<title>nix-prefetch-url</title>
<xi:include href="nix-prefetch-url.xml" />
</section>
<section>
<section xml:id="sec-nix-pull">
<title>nix-pull</title>
<xi:include href="nix-pull.xml" />
</section>
@@ -93,7 +104,7 @@
<title>nix-push</title>
<xi:include href="nix-push.xml" />
</section>
<section>
<section xml:id="sec-nix-unpack-closure">
<title>nix-unpack-closure</title>
<xi:include href="nix-unpack-closure.xml" />
</section>

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-build</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-build</refname>
@@ -9,8 +17,9 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-build</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-channel</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-channel</refname>
<refpurpose>manage Nix channels</refpurpose>
@@ -54,11 +62,11 @@ also <xref linkend="sec-channels" />.</para>
<varlistentry><term><option>--update</option></term>
<listitem><para>Downloads the Nix expressions of all subscribed
channels, makes the conjunction of these the default for
<command>nix-env</command> operations (by calling <command>nix-env
-I</command>), and performs a <command>nix-pull</command> on the
manifests of all channels to make pre-built binaries
available.</para></listitem>
channels, makes them the default for <command>nix-env</command>
operations (by symlinking them in the directory
<filename>~/.nix-defexpr</filename>), and performs a
<command>nix-pull</command> on the manifests of all channels to
make pre-built binaries available.</para></listitem>
</varlistentry>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-collect-garbage</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-collect-garbage</refname>
<refpurpose>delete unreachable store paths</refpurpose>

View File

@@ -0,0 +1,151 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-copy-closure</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-copy-closure</refname>
<refpurpose>copy a closure to or from a remote machine via SSH</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-copy-closure</command>
<group>
<arg choice='plain'><option>--to</option></arg>
<arg choice='plain'><option>--from</option></arg>
</group>
<arg><option>--sign</option></arg>
<arg><option>--gzip</option></arg>
<arg choice='plain'>
<arg><replaceable>user@</replaceable></arg><replaceable>machine</replaceable>
</arg>
<arg choice='plain'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsection><title>Description</title>
<para><command>nix-copy-closure</command> gives you an easy and
efficient way to exchange software between machines. Given one or
more Nix store paths <replaceable>paths</replaceable> on the local
machine, <command>nix-copy-closure</command> computes the closure of
those paths (i.e. all their dependencies in the Nix store), and copies
all paths in the closure to the remote machine via the
<command>ssh</command> (Secure Shell) command. With the
<option>--from</option>, the direction is reversed:
the closure of <replaceable>paths</replaceable> on a remote machine is
copied to the Nix store on the local machine.</para>
<para>This command is efficient because it only sends the store paths
that are missing on the target machine.</para>
<para>Since <command>nix-copy-closure</command> calls
<command>ssh</command>, you may be asked to type in the appropriate
password or passphrase. In fact, you may be asked
<emphasis>twice</emphasis> because <command>nix-copy-closure</command>
currently connects twice to the remote machine, first to get the set
of paths missing on the target machine, and second to send the dump of
those paths. If this bothers you, use
<command>ssh-agent</command>.</para>
<refsection><title>Options</title>
<variablelist>
<varlistentry><term><option>--to</option></term>
<listitem><para>Copy the closure of
<replaceable>paths</replaceable> from the local Nix store to the
Nix store on <replaceable>machine</replaceable>. This is the
default.</para></listitem>
</varlistentry>
<varlistentry><term><option>--from</option></term>
<listitem><para>Copy the closure of
<replaceable>paths</replaceable> from the Nix store on
<replaceable>machine</replaceable> to the local Nix
store.</para></listitem>
</varlistentry>
<varlistentry><term><option>--sign</option></term>
<listitem><para>Let the sending machine cryptographically sign the
dump of each path with the key in
<filename>/nix/etc/nix/signing-key.sec</filename>. If the user on
the target machine does not have direct access to the Nix store
(i.e., if the target machine has a multi-user Nix installation),
then the target machine will check the dump against
<filename>/nix/etc/nix/signing-key.pub</filename> before unpacking
it in its Nix store. This allows secure sharing of store paths
between untrusted users on two machines, provided that there is a
trust relation between the Nix installations on both machines
(namely, they have matching public/secret keys).</para></listitem>
</varlistentry>
<varlistentry><term><option>--gzip</option></term>
<listitem><para>Compress the dump of each path with
<command>gzip</command> before sending it.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><title>Environment variables</title>
<variablelist>
<varlistentry><term><envar>NIX_SSHOPTS</envar></term>
<listitem><para>Additional options to be passed to
<command>ssh</command> on the command line.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
<refsection><title>Examples</title>
<para>Copy Firefox with all its dependencies to a remote machine:
<screen>
$ nix-copy-closure alice@itchy.labs $(type -tP firefox)</screen>
</para>
<para>Copy Subversion from a remote machine and then install it into a
user environment:
<screen>
$ nix-copy-closure --from alice@itchy.labs \
/nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
$ nix-env -i /nix/store/0dj0503hjxy5mbwlafv1rsbdiyx1gkdy-subversion-1.4.4
</screen>
</para>
</refsection>
</refsection>
</refentry>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-env</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-env</refname>
<refpurpose>manipulate or query Nix user environments</refpurpose>
@@ -9,15 +17,9 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-env</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
</group>
<replaceable>attrPath</replaceable>
</arg>
<arg><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--file</option></arg>
@@ -37,9 +39,6 @@
<replaceable>system</replaceable>
</arg>
<arg><option>--dry-run</option></arg>
<arg><option>--from-expression</option></arg>
<arg><option>-E</option></arg>
<arg><option>--from-profile</option> <replaceable>path</replaceable></arg>
<arg choice='plain'><replaceable>operation</replaceable></arg>
<arg rep='repeat'><replaceable>options</replaceable></arg>
<arg rep='repeat'><replaceable>arguments</replaceable></arg>
@@ -50,7 +49,7 @@
<refsection><title>Description</title>
<para>The command <command>nix-env</command> is used to manipulate Nix
user environments. User environments are sets of software components
user environments. User environments are sets of software packages
available to a user at some point in time. In other words, they are a
synthesised view of the programs available in the Nix store. There
may be many user environments: different users can have different
@@ -142,14 +141,34 @@ linkend="sec-common-options" />.</para>
<variablelist>
<varlistentry><term><filename>~/.nix-defexpr</filename></term>
<listitem><para>The default Nix expression used by the
<option>--install</option>, <option>--upgrade</option>, and
<option>--query --available</option> operations to obtain
derivations. It is generally a symbolic link to some other
location set using the <option>--import</option> operation. The
<listitem><para>A directory that contains the default Nix
expressions used by the <option>--install</option>,
<option>--upgrade</option>, and <option>--query
--available</option> operations to obtain derivations. The
<option>--file</option> option may be used to override this
default.</para></listitem>
default.</para>
<para>The Nix expressions in this directory are combined into a
single attribute set, with each file as an attribute that has the
name of the file. Thus, if <filename>~/.nix-defexpr</filename>
contains two files, <filename>foo</filename> and
<filename>bar</filename>, then the default Nix expression will
essentially be
<programlisting>
{
foo = import ~/.nix-defexpr/foo;
bar = import ~/.nix-defexpr/bar;
}</programlisting>
</para>
<para>The command <command>nix-channel</command> places symlinks
to the downloaded Nix expressions from each subscribed channel in
this directory.</para>
</listitem>
</varlistentry>
@@ -182,6 +201,7 @@ linkend="sec-common-options" />.</para>
<arg choice='plain'><option>--install</option></arg>
<arg choice='plain'><option>-i</option></arg>
</group>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-inst-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<group choice='opt'>
<arg choice='plain'><option>--preserve-installed</option></arg>
<arg choice='plain'><option>-P</option></arg>
@@ -213,11 +233,21 @@ number of possible ways:
<para>If there are multiple derivations matching a name in
<replaceable>args</replaceable> that have the same name (e.g.,
<literal>gcc-3.3.6</literal> and <literal>gcc-4.1.1</literal>), then
only the highest version will be installed. You can force the
installation of multiple derivations with the same name by being
specific about the versions. For instance, <literal>nix-env -i
gcc-3.3.6 gcc-4.1.1</literal> will install both version of GCC (and
will probably cause a user environment conflict!).</para></listitem>
the derivation with the highest <emphasis>priority</emphasis> is
used. A derivation can define a priority by declaring the
<varname>meta.priority</varname> attribute. This attribute should
be a number, with a higher value denoting a lower priority. The
default priority is <literal>0</literal>.</para>
<para>If there are multiple matching derivations with the same
priority, then the derivation with the highest version will be
installed.</para>
<para>You can force the installation of multiple derivations with
the same name by being specific about the versions. For instance,
<literal>nix-env -i gcc-3.3.6 gcc-4.1.1</literal> will install both
version of GCC (and will probably cause a user environment
conflict!).</para></listitem>
<listitem><para>If <link
linkend='opt-attr'><option>--attr</option></link>
@@ -264,6 +294,15 @@ number of possible ways:
<variablelist>
<varlistentry><term><option>--prebuild-only</option> / <option>-b</option></term>
<listitem><para>Use only derivations for which a substitute is
registered, i.e., there is a pre-built binary available that can
be downloaded in lieu of building the derivation. Thus, no
packages will be built from source.</para></listitem>
</varlistentry>
<varlistentry><term><option>--preserve-installed</option></term>
<term><option>-P</option></term>
@@ -379,7 +418,7 @@ the following paths will be substituted:
<!--######################################################################-->
<refsection><title>Operation <option>--upgrade</option></title>
<refsection xml:id="rsec-nix-env-upgrade"><title>Operation <option>--upgrade</option></title>
<refsection><title>Synopsis</title>
@@ -389,6 +428,7 @@ the following paths will be substituted:
<arg choice='plain'><option>--upgrade</option></arg>
<arg choice='plain'><option>-u</option></arg>
</group>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-inst-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<group choice='opt'>
<arg choice='plain'><option>--lt</option></arg>
<arg choice='plain'><option>--leq</option></arg>
@@ -463,6 +503,9 @@ installed.</para>
</variablelist>
<para>For the other flags, see <option
linkend="rsec-nix-env-install">--install</option>.</para>
</refsection>
<refsection><title>Examples</title>
@@ -572,6 +615,111 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
<!--######################################################################-->
<refsection xml:id="rsec-nix-env-set-flag"><title>Operation <option>--set-flag</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-env</command>
<arg choice='plain'><option>--set-flag</option></arg>
<arg choice='plain'><replaceable>name</replaceable></arg>
<arg choice='plain'><replaceable>value</replaceable></arg>
<arg choice='plain' rep='repeat'><replaceable>drvnames</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The <option>--set-flag</option> operation allows meta attributes
of installed packages to be modified. There are several attributes
that can be usefully modified, because they affect the behaviour of
<command>nix-env</command> or the user environment build
script:
<itemizedlist>
<listitem><para><varname>priority</varname> can be changed to
resolve filename clashes. The user environment build script uses
the <varname>meta.priority</varname> attribute of derivations to
resolve filename collisions between packages. Lower priority values
denote a higher priority. For instance, the GCC wrapper package and
the Binutils package in Nixpkgs both have a file
<filename>bin/ld</filename>, so previously if you tried to install
both you would get a collision. Now, on the other hand, the GCC
wrapper declares a higher priority than Binutils, so the formers
<filename>bin/ld</filename> is symlinked in the user
environment.</para></listitem>
<listitem><para><varname>keep</varname> can be set to
<literal>true</literal> to prevent the package from being upgraded
or replaced. This is useful if you want to hang on to an older
version of a package.</para></listitem>
<listitem><para><varname>active</varname> can be set to
<literal>false</literal> to “disable” the package. That is, no
symlinks will be generated to the files of the package, but it
remains part of the profile (so it wont be garbage-collected). It
can be set back to <literal>true</literal> to re-enable the
package.</para></listitem>
</itemizedlist>
</para>
</refsection>
<refsection><title>Examples</title>
<para>To prevent the currently installed Firefox from being upgraded:
<screen>
$ nix-env --set-flag keep true firefox</screen>
After this, <command>nix-env -u</command> will ignore Firefox.</para>
<para>To disable the currently installed Firefox, then install a new
Firefox while the old remains part of the profile:
<screen>
$ nix-env -q \*
firefox-2.0.0.9 <lineannotation>(the current one)</lineannotation>
$ nix-env --preserve-installed -i firefox-2.0.0.11
installing `firefox-2.0.0.11'
building path(s) `/nix/store/myy0y59q3ig70dgq37jqwg1j0rsapzsl-user-environment'
Collission between `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.11/bin/firefox'
and `/nix/store/<replaceable>...</replaceable>-firefox-2.0.0.9/bin/firefox'.
<lineannotation>(i.e., cant have two active at the same time)</lineannotation>
$ nix-env --set-flag active false firefox
setting flag on `firefox-2.0.0.9'
$ nix-env --preserve-installed -i firefox-2.0.0.11
installing `firefox-2.0.0.11'
$ nix-env -q \*
firefox-2.0.0.11 <lineannotation>(the enabled one)</lineannotation>
firefox-2.0.0.9 <lineannotation>(the disabled one)</lineannotation></screen>
</para>
<para>To make files from <literal>binutils</literal> take precedence
over files from <literal>gcc</literal>:
<screen>
$ nix-env --set-flag priority 5 binutils
$ nix-env --set-flag priority 10 gcc</screen>
</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--query</option></title>
@@ -584,13 +732,14 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
<arg choice='plain'><option>--query</option></arg>
<arg choice='plain'><option>-q</option></arg>
</group>
<arg><option>--xml</option></arg>
<group choice='opt'>
<arg choice='plain'><option>--installed</option></arg>
<arg choice='plain'><option>--available</option></arg>
<arg choice='plain'><option>-a</option></arg>
</group>
<sbr />
<arg>
<group choice='req'>
<arg choice='plain'><option>--status</option></arg>
@@ -599,8 +748,8 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
</arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
<arg choice='plain'><option>--attr-path</option></arg>
<arg choice='plain'><option>-P</option></arg>
</group>
</arg>
<arg><option>--no-name</option></arg>
@@ -614,6 +763,28 @@ $ nix-env -e '*' <lineannotation>(remove everything)</lineannotation></screen>
<arg><option>--drv-path</option></arg>
<arg><option>--out-path</option></arg>
<arg><option>--description</option></arg>
<arg><option>--meta</option></arg>
<sbr />
<arg><option>--xml</option></arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--prebuilt-only</option></arg>
<arg choice='plain'><option>-b</option></arg>
</group>
</arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
</group>
<replaceable>attribute-path</replaceable>
</arg>
<sbr />
<arg choice='plain' rep='repeat'><replaceable>names</replaceable></arg>
</cmdsynopsis>
@@ -690,6 +861,16 @@ user environment elements, etc. -->
</varlistentry>
<varlistentry><term><option>--prebuild-only</option> / <option>-b</option></term>
<listitem><para>Show only derivations for which a substitute is
registered, i.e., there is a pre-built binary available that can
be downloaded in lieu of building the derivation. Thus, this
shows all packages that probably can be installed
quickly.</para></listitem>
</varlistentry>
<varlistentry><term><option>--status</option></term>
<term><option>-s</option></term>
@@ -709,8 +890,8 @@ user environment elements, etc. -->
</varlistentry>
<varlistentry><term><option>--attr</option></term>
<term><option>-a</option></term>
<varlistentry><term><option>--attr-path</option></term>
<term><option>-P</option></term>
<listitem><para>Print the <emphasis>attribute path</emphasis> of
the derivation, which can be used to unambiguously select it using
@@ -733,35 +914,35 @@ user environment elements, etc. -->
<listitem><para>Compare installed versions to available versions,
or vice versa (if <option>--available</option> is given). This is
useful for quickly seeing whether upgrades for installed
components are available in a Nix expression. A column is added
packages are available in a Nix expression. A column is added
with the following meaning:
<variablelist>
<varlistentry><term><literal>&lt;</literal> <replaceable>version</replaceable></term>
<listitem><para>A newer version of the component is available
<listitem><para>A newer version of the package is available
or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>=</literal> <replaceable>version</replaceable></term>
<listitem><para>At most the same version of the component is
<listitem><para>At most the same version of the package is
available or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>></literal> <replaceable>version</replaceable></term>
<listitem><para>Only older versions of the component are
<listitem><para>Only older versions of the package are
available or installed.</para></listitem>
</varlistentry>
<varlistentry><term><literal>- ?</literal></term>
<listitem><para>No version of the component is available or
<listitem><para>No version of the package is available or
installed.</para></listitem>
</varlistentry>
@@ -802,6 +983,14 @@ user environment elements, etc. -->
</varlistentry>
<varlistentry><term><option>--meta</option></term>
<listitem><para>Print all of the meta-attributes of the
derivation. This option is only available with
<option>--xml</option>.</para></listitem>
</varlistentry>
</variablelist>
</refsection>
@@ -1061,43 +1250,4 @@ error: no generation older than the current (91) exists</screen>
<!--######################################################################-->
<refsection><title>Operation <option>--import</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-env</command>
<group choice='req'>
<arg choice='plain'><option>--import</option></arg>
<arg choice='plain'><option>-I</option></arg>
</group>
<arg choice='req'><replaceable>path</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>This operation makes <replaceable>path</replaceable> the default
active Nix expression for the user. That is, the symlink
<filename>~/.nix-userenv</filename> is made to point to
<replaceable>path</replaceable>.</para>
</refsection>
<refsection><title>Examples</title>
<screen>
$ nix-env -I ~/nixpkgs-0.5/</screen>
</refsection>
</refsection>
</refentry>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-hash</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-hash</refname>
<refpurpose>compute the cryptographic hash of a path</refpurpose>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-install-package</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-install-package</refname>
<refpurpose>install a Nix Package file</refpurpose>

View File

@@ -1,6 +1,14 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-instantiate</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-instantiate</refname>
<refpurpose>instantiate store derivations from Nix expressions</refpurpose>
@@ -9,7 +17,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-instantiate</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--arg</option> <replaceable>name</replaceable> <replaceable>value</replaceable></arg>
<arg>
<group choice='req'>

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-pack-closure</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-pack-closure</refname>
@@ -58,6 +66,16 @@ $ nix-pack-closure $(which azureus) | ssh scratchy nix-unpack-closure</screen>
</para>
<para>As a variation on the previous example, copy
<command>azureus</command>, and also install it in the users profile
on the target machine:
<screen>
$ nix-pack-closure $(which azureus) | ssh scratchy 'nix-env -i $(nix-unpack-closure)'</screen>
</para>
</refsection>

View File

@@ -1,5 +1,14 @@
<refentry>
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-prefetch-url</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-prefetch-url</refname>
<refpurpose>copy a file from a URL into the store and print its MD5 hash</refpurpose>
@@ -38,7 +47,7 @@ avoided.</para>
<para>The environment variable <envar>NIX_HASH_ALGO</envar> specifies
which hash algorithm to use. It can be either <literal>md5</literal>,
<literal>sha1</literal>, or <literal>sha256</literal>. The default is
<literal>md5</literal>.</para>
<literal>sha256</literal>.</para>
<para>If <replaceable>hash</replaceable> is specified, then a download
is not performed if the Nix store already contains a file with the

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-pull</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-pull</refname>

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-push</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-push</refname>

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-store</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-store</refname>
@@ -9,7 +17,7 @@
<refsynopsisdiv>
<cmdsynopsis>
<command>nix-store</command>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xpointer(/nop/*)" />
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="opt-common-syn.xml#xmlns(db=http://docbook.org/ns/docbook)xpointer(/db:nop/*)" />
<arg><option>--add-root</option> <replaceable>path</replaceable></arg>
<arg><option>--indirect</option></arg>
<arg choice='plain'><replaceable>operation</replaceable></arg>
@@ -651,37 +659,7 @@ $ gv graph.ps</screen>
<!--######################################################################-->
<!--
<refsection><title>Operation <option>-XXX-substitute</option></title>
<refsection><title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>-XXX-substitute</option></arg>
<arg choice='plain'
rep='repeat'><replaceable>srcpath</replaceable> <replaceable>subpath</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>-XXX-substitute</option> registers that the
store path <replaceable>srcpath</replaceable> can be built by
realising the derivation expression in
<replaceable>subpath</replaceable>. This is used to implement binary
deployment.</para>
</refsection>
</refsection>
-->
<!--######################################################################-->
<refsection><title>Operation <option>--verify</option></title>
<refsection xml:id='refsec-nix-store-verify'><title>Operation <option>--verify</option></title>
<refsection>
<title>Synopsis</title>
@@ -801,4 +779,178 @@ archive is read from standard input.</para>
</refsection>
<!--######################################################################-->
<refsection xml:id='refsec-nix-store-export'><title>Operation <option>--export</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--export</option></arg>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--export</option> writes a serialisation
of the specified store paths to standard output in a format that can
be imported into another Nix store with <command
linkend="refsec-nix-store-import">nix-store --import</command>. This
is like <command linkend="refsec-nix-store-dump">nix-store
--dump</command>, except that the NAR archive produced by that command
doesnt contain the necessary meta-information to allow it to be
imported into another Nix store (namely, the set of references of the
path).</para>
<para>This command does not produce a <emphasis>closure</emphasis> of
the specified paths, so if a store path references other store paths
that are missing in the target Nix store, the import will fail. To
copy a whole closure, do something like
<screen>
$ nix-store --export $(nix-store -qR <replaceable>paths</replaceable>) > out</screen>
</para>
<para>For an example of how <option>--export</option> and
<option>--import</option> can be used, see the source of the <command
linkend="sec-nix-copy-closure">nix-copy-closure</command>
command.</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection xml:id='refsec-nix-store-import'><title>Operation <option>--import</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--import</option></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--export</option> reads a serialisation of
a set of store paths produced by <command
linkend="refsec-nix-store-export">nix-store --import</command> from
standard input and adds those store paths to the Nix store. Paths
that already exist in the Nix store are ignored. If a path refers to
another path that doesnt exist in the Nix store, the import
fails.</para>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--optimise</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<arg choice='plain'><option>--optimise</option></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--optimise</option> reduces Nix store disk
space usage by finding identical files in the store and hard-linking
them to each other. It typically reduces the size of the store by
something like 25-35%. Only regular files and symlinks are
hard-linked in this manner. Files are considered identical when they
have the same NAR archive serialisation: that is, regular files must
have the same contents and permission (executable or non-executable),
and symlinks must have the same contents.</para>
<para>After completion, or when the command is interrupted, a report
on the achieved savings is printed on standard error.</para>
<para>Use <option>-vv</option> or <option>-vvv</option> to get some
progress indication.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store --optimise
hashing files in `/nix/store/qhqx7l2f1kmwihc9bnxs7rc159hsxnf3-gcc-4.1.1'
<replaceable>...</replaceable>
541838819 bytes (516.74 MiB) freed by hard-linking 54143 files;
there are 114486 files with equal contents out of 215894 files in total
</screen>
</refsection>
</refsection>
<!--######################################################################-->
<refsection><title>Operation <option>--read-log</option></title>
<refsection>
<title>Synopsis</title>
<cmdsynopsis>
<command>nix-store</command>
<group choice='req'>
<arg choice='plain'><option>--read-log</option></arg>
<arg choice='plain'><option>-l</option></arg>
</group>
<arg choice='plain' rep='repeat'><replaceable>paths</replaceable></arg>
</cmdsynopsis>
</refsection>
<refsection><title>Description</title>
<para>The operation <option>--read-log</option> prints the build log
of the specified store paths on standard output. The build log is
whatever the builder of a derivation wrote to standard output and
standard error. If a store path is not a derivation, the deriver of
the store path is used.</para>
<para>Build logs are kept in
<filename>/nix/var/log/nix/drvs</filename>. However, there is no
guarantee that a build log is available for any particular store
path. For instance, if the path was downloaded as a pre-built binary
through a substitute, then the log is unavailable.</para>
</refsection>
<refsection><title>Example</title>
<screen>
$ nix-store -l $(which ktorrent)
building /nix/store/dhc73pvzpnzxhdgpimsd9sw39di66ph1-ktorrent-2.2.1
unpacking sources
unpacking source archive /nix/store/p8n1jpqs27mgkjw07pb5269717nzf5f8-ktorrent-2.2.1.tar.gz
ktorrent-2.2.1/
ktorrent-2.2.1/NEWS
<replaceable>...</replaceable>
</screen>
</refsection>
</refsection>
<!-- TODO: export, import operations -->
</refentry>

View File

@@ -1,5 +1,13 @@
<refentry xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refmeta>
<refentrytitle>nix-unpack-closure</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Nix</refmiscinfo>
<refmiscinfo class="version"><xi:include href="version.txt" parse="text"/></refmiscinfo>
</refmeta>
<refnamediv>
<refname>nix-unpack-closure</refname>
@@ -22,6 +30,12 @@ closure is a single file read from standard input. See the
description of <command>nix-pack-closure</command> for details and
examples.</para>
<para>The top-level paths in the closure (i.e., the paths passed to
the original <command>nix-pack-closure</command> call that created the
closure) are printed on standard output. These paths can be passed,
for instance, to <literal>nix-env -i</literal> to install them into a
user environment on the target machine.</para>
</refsection>

View File

@@ -1,4 +1,4 @@
<nop>
<nop xmlns="http://docbook.org/ns/docbook">
<arg><option>--help</option></arg>
<arg><option>--version</option></arg>
@@ -13,6 +13,10 @@
</group>
<replaceable>number</replaceable>
</arg>
<arg>
<arg><option>--max-silent-time</option></arg>
<replaceable>number</replaceable>
</arg>
<arg><option>--keep-going</option></arg>
<arg><option>-k</option></arg>
<arg><option>--keep-failed</option></arg>

View File

@@ -103,6 +103,17 @@
</varlistentry>
<varlistentry xml:id="opt-max-silent-time"><term><option>--max-silent-time</option></term>
<listitem><para>Sets the maximum number of seconds that a builder
can go without producing any data on standard output or standard
error. The default is specified by the <link
linkend='conf-build-max-silent-time'><literal>build-max-silent-time</literal></link>
configuration setting. <literal>0</literal> means no
time-out.</para></listitem>
</varlistentry>
<varlistentry><term><option>--keep-going</option></term>
<term><option>-k</option></term>
@@ -257,6 +268,17 @@
</varlistentry>
<varlistentry><term><option>--argstr</option> <replaceable>name</replaceable> <replaceable>value</replaceable></term>
<listitem><para>This option is like <option>--arg</option>, only the
value is not a Nix expression but a string. So instead of
<literal>--arg system \"i686-linux\"</literal> (the outer quotes are
to keep the shell happy) you can say <literal>--argstr system
i686-linux</literal>.</para></listitem>
</varlistentry>
<varlistentry xml:id="opt-attr"><term><option>--attr</option> / <option>-A</option>
<replaceable>attrPath</replaceable></term>

View File

@@ -0,0 +1,22 @@
<nop xmlns="http://docbook.org/ns/docbook">
<arg>
<group choice='req'>
<arg choice='plain'><option>--prebuilt-only</option></arg>
<arg choice='plain'><option>-b</option></arg>
</group>
</arg>
<arg>
<group choice='req'>
<arg choice='plain'><option>--attr</option></arg>
<arg choice='plain'><option>-A</option></arg>
</group>
</arg>
<arg><option>--from-expression</option></arg>
<arg><option>-E</option></arg>
<arg><option>--from-profile</option> <replaceable>path</replaceable></arg>
</nop>

View File

@@ -6,9 +6,9 @@
<para>This chapter discusses how to do package management with Nix,
i.e., how to obtain, install, upgrade, and erase components. This is
i.e., how to obtain, install, upgrade, and erase packages. This is
the “users” perspective of the Nix system — people
who want to <emphasis>create</emphasis> components should consult
who want to <emphasis>create</emphasis> packages should consult
<xref linkend='chap-writing-nix-expressions' />.</para>
@@ -16,8 +16,8 @@ who want to <emphasis>create</emphasis> components should consult
<para>The main command for package management is <link
linkend="sec-nix-env"><command>nix-env</command></link>. You can use
it to install, upgrade, and erase components, and to query what
components are installed or are available for installation.</para>
it to install, upgrade, and erase packages, and to query what
packages are installed or are available for installation.</para>
<para>In Nix, different users can have different “views”
on the set of installed applications. That is, there might be lots of
@@ -30,10 +30,10 @@ environment</emphasis>, which is just a directory tree consisting of
symlinks to the files of the active applications. </para>
<para>Components are installed from a set of <emphasis>Nix
expressions</emphasis> that tell Nix how to build those components,
expressions</emphasis> that tell Nix how to build those packages,
including, if necessary, their dependencies. There is a collection of
Nix expressions called the Nix Package collection that contains
components ranging from basic development stuff such as GCC and Glibc,
packages ranging from basic development stuff such as GCC and Glibc,
to end-user applications like Mozilla Firefox. (Nix is however not
tied to the Nix Package collection; you could write your own Nix
expressions based on it, or completely new ones.) You can download
@@ -41,7 +41,7 @@ the latest version from <link
xlink:href='http://nix.cs.uu.nl/dist/nix' />.</para>
<para>Assuming that you have downloaded and unpacked a release of Nix
Packages, you can view the set of available components in the release:
Packages, you can view the set of available packages in the release:
<screen>
$ nix-env -qaf nixpkgs-<replaceable>version</replaceable> '*'
@@ -74,7 +74,7 @@ gcc-4.1.1</screen>
</para>
<para>It is also possible to see the <emphasis>status</emphasis> of
available components, i.e., whether they are installed into the user
available packages, i.e., whether they are installed into the user
environment and/or present in the system:
<screen>
@@ -86,24 +86,24 @@ IPS bison-1.875d
...</screen>
The first character (<literal>I</literal>) indicates whether the
component is installed in your current user environment. The second
package is installed in your current user environment. The second
(<literal>P</literal>) indicates whether it is present on your system
(in which case installing it into your user environment would be a
very quick operation). The last one (<literal>S</literal>) indicates
whether there is a so-called <emphasis>substitute</emphasis> for the
component, which is Nixs mechanism for doing binary deployment. It
just means that Nix know that it can fetch a pre-built component from
package, which is Nixs mechanism for doing binary deployment. It
just means that Nix knows that it can fetch a pre-built package from
somewhere (typically a network server) instead of building it
locally.</para>
<para>So now that we have a set of Nix expressions we can build the
components contained in them. This is done using <literal>nix-env
packages contained in them. This is done using <literal>nix-env
-i</literal>. For instance,
<screen>
$ nix-env -f nixpkgs-<replaceable>version</replaceable> -i subversion</screen>
will install the component called <literal>subversion</literal> (which
will install the package called <literal>subversion</literal> (which
is, of course, the <link
xlink:href='http://subversion.tigris.org/'>Subversion version
management system</link>).</para>
@@ -112,7 +112,7 @@ management system</link>).</para>
Subversion and all its dependencies. This will take quite a while —
typically an hour or two on modern machines. Fortunately, there is a
faster way (so do a Ctrl-C on that install operation!): you just need
to tell Nix that pre-built binaries of all those components are
to tell Nix that pre-built binaries of all those packages are
available somewhere. This is done using the
<command>nix-pull</command> command, which must be supplied with a URL
containing a <emphasis>manifest</emphasis> describing what binaries
@@ -153,7 +153,7 @@ expressions, use <parameter>-i</parameter> instead of
<parameter>-u</parameter>; <parameter>-i</parameter> will remove
whatever version is already installed.</para>
<para>You can also upgrade all components for which there are newer
<para>You can also upgrade all packages for which there are newer
versions:
<screen>
@@ -199,19 +199,19 @@ set.</para></footnote></para>
implementing the ability to allow different users to have different
configurations, and to do atomic upgrades and rollbacks. To
understand how they work, its useful to know a bit about how Nix
works. In Nix, components are stored in unique locations in the
works. In Nix, packages are stored in unique locations in the
<emphasis>Nix store</emphasis> (typically,
<filename>/nix/store</filename>). For instance, a particular version
of the Subversion component might be stored in a directory
of the Subversion package might be stored in a directory
<filename>/nix/store/dpmvp969yhdqs7lm2r1a3gng7pyq6vy4-subversion-1.1.3/</filename>,
while another version might be stored in
<filename>/nix/store/5mq2jcn36ldlmh93yj1n8s9c95pj7c5s-subversion-1.1.2</filename>.
The long strings prefixed to the directory names are cryptographic
hashes<footnote><para>160-bit truncations of SHA-256 hashes encoded in
a base-32 notation, to be precise.</para></footnote> of
<emphasis>all</emphasis> inputs involved in building the component
<emphasis>all</emphasis> inputs involved in building the package
sources, dependencies, compiler flags, and so on. So if two
components differ in any way, they end up in different locations in
packages differ in any way, they end up in different locations in
the file system, so they dont interfere with each other. <xref
linkend='fig-user-environments' /> shows a part of a typical Nix
store.</para>
@@ -231,12 +231,12 @@ $ /nix/store/dpmvp969yhdq...-subversion-1.1.3/bin/svn</screen>
every time you want to run Subversion. Of course we could set up the
<envar>PATH</envar> environment variable to include the
<filename>bin</filename> directory of every component we want to use,
<filename>bin</filename> directory of every package we want to use,
but this is not very convenient since changing <envar>PATH</envar>
doesnt take effect for already existing processes. The solution Nix
uses is to create directory trees of symlinks to
<emphasis>activated</emphasis> components. These are called
<emphasis>user environments</emphasis> and they are components
<emphasis>activated</emphasis> packages. These are called
<emphasis>user environments</emphasis> and they are packages
themselves (though automatically generated by
<command>nix-env</command>), so they too reside in the Nix store. For
instance, in <xref linkend='fig-user-environments' /> the user
@@ -285,8 +285,8 @@ operation, a new user environment and generation link are created
based on the current one, and finally the <filename>default</filename>
symlink is made to point at the new generation. This last step is
atomic on Unix, which explains how we can do atomic upgrades. (Note
that the building/installing of new components doesnt interfere in
any way with old components, since they are stored in different
that the building/installing of new packages doesnt interfere in
any way with old packages, since they are stored in different
locations in the Nix store.)</para>
<para>If you find that you want to undo a <command>nix-env</command>
@@ -352,18 +352,18 @@ This will <emphasis>not</emphasis> change the
<para><command>nix-env</command> operations such as upgrades
(<option>-u</option>) and uninstall (<option>-e</option>) never
actually delete components from the system. All they do (as shown
actually delete packages from the system. All they do (as shown
above) is to create a new user environment that no longer contains
symlinks to the “deleted” components.</para>
symlinks to the “deleted” packages.</para>
<para>Of course, since disk space is not infinite, unused components
<para>Of course, since disk space is not infinite, unused packages
should be removed at some point. You can do this by running the Nix
garbage collector. It will remove from the Nix store any component
garbage collector. It will remove from the Nix store any package
not used (directly or indirectly) by any generation of any
profile.</para>
<para>Note however that as long as old generations reference a
component, it will not be deleted. After all, we wouldnt be able to
package, it will not be deleted. After all, we wouldnt be able to
do a rollback otherwise. So in order for garbage collection to be
effective, you should also delete (some) old generations. Of course,
this should only be done if you are certain that you will not need to
@@ -486,7 +486,7 @@ makes the union of each channels Nix expressions the default for
<screen>
$ nix-env -u '*'</screen>
to upgrade all components in your profile to the latest versions
to upgrade all packages in your profile to the latest versions
available in the subscribed channels.</para>
</section>

View File

@@ -11,7 +11,7 @@ to the following chapters.</para>
<orderedlist>
<listitem><para>Download a source tarball or RPM from <link
xlink:href='http://www.cs.uu.nl/groups/ST/Trace/Nix'/>. Build source
xlink:href='http://nix.cs.uu.nl/'/>. Build source
distributions using the regular sequence:
<screen>
@@ -22,8 +22,9 @@ $ make install <lineannotation>(as root)</lineannotation></screen>
This will install Nix in <filename>/nix</filename>. You shouldn't
change the prefix if at all possible since that will make it
impossible to use our pre-built components. Alternatively, you could
grab an RPM if you're on an RPM-based system. You should also add
impossible to use pre-built binaries from the Nixpkgs channel and
other channels. Alternatively, you could grab an RPM if you're on an
RPM-based system. You should also add
<filename>/nix/etc/profile.d/nix.sh</filename> to your
<filename>~/.bashrc</filename> (or some other login
file).</para></listitem>
@@ -40,14 +41,14 @@ $ nix-channel --add \
<screen>
$ nix-channel --update</screen>
Note that this in itself doesn't download any components, it just
Note that this in itself doesn't download any packages, it just
downloads the Nix expressions that build them and stores them
somewhere (under <filename>~/.nix-defexpr</filename>, in case you're
curious). Also, it registers the fact that pre-built binaries are
available remotely.</para></listitem>
<listitem><para>See what installable components are currently
available in the channel:
<listitem><para>See what installable packages are currently available
in the channel:
<screen>
$ nix-env -qa * <lineannotation>(mind the quotes!)</lineannotation>
@@ -59,13 +60,13 @@ libxslt-1.1.0
</para></listitem>
<listitem><para>Install some components from the channel:
<listitem><para>Install some packages from the channel:
<screen>
$ nix-env -i hello firefox <replaceable>...</replaceable> </screen>
This should download the pre-built components; it should not build
them locally (if it does, something went wrong).</para></listitem>
This should download pre-built packages; it should not build them
locally (if it does, something went wrong).</para></listitem>
<listitem><para>Test that they work:
@@ -92,8 +93,8 @@ $ nix-env -e hello</screen>
$ nix-channel --update
$ nix-env -u '*'</screen>
The latter command will upgrade each installed component for which
there is a “newer” version (as determined by comparing the version
The latter command will upgrade each installed package for which there
is a “newer” version (as determined by comparing the version
numbers).</para></listitem>
<listitem><para>You can also install specific packages directly from
@@ -107,7 +108,7 @@ appear asking you whether its okay to install the package. Say
installed.</para></listitem>
<listitem><para>If you're unhappy with the result of a
<command>nix-env</command> action (e.g., an upgraded component turned
<command>nix-env</command> action (e.g., an upgraded package turned
out not to work properly), you can go back:
<screen>
@@ -124,7 +125,7 @@ $ nix-collect-garbage -d</screen>
<!--
The first command deletes old “generations” of your profile (making
rollbacks impossible, but also making the components in those old
rollbacks impossible, but also making the packages in those old
generations available for garbage collection), while the second
command actually deletes them.-->

View File

@@ -1,10 +1,297 @@
<article xmlns="http://docbook.org/ns/docbook"
xmlns:xlink="http://www.w3.org/1999/xlink">
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:id="sec-relnotes">
<title>Nix Release Notes</title>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.12"><title>Release 0.12 (TBA)</title>
<itemizedlist>
<listitem><para><command>nix-store --dump-db / --load-db</command>.</para></listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section xml:id="ssec-relnotes-0.11"><title>Release 0.11 (December 31,
2007)</title>
<para>Nix 0.11 has many improvements over the previous stable release.
The most important improvement is secure multi-user support. It also
features many usability enhancements and language extensions, many of
them prompted by NixOS, the purely functional Linux distribution based
on Nix. Here is an (incomplete) list:</para>
<itemizedlist>
<listitem><para>Secure multi-user support. A single Nix store can
now be shared between multiple (possible untrusted) users. This is
an important feature for NixOS, where it allows non-root users to
install software. The old setuid method for sharing a store between
multiple users has been removed. Details for setting up a
multi-user store can be found in the manual.</para></listitem>
<listitem><para>The new command <command>nix-copy-closure</command>
gives you an easy and efficient way to exchange software between
machines. It copies the missing parts of the closure of a set of
store path to or from a remote machine via
<command>ssh</command>.</para></listitem>
<listitem><para>A new kind of string literal: strings between double
single-quotes (<literal>''</literal>) have indentation
“intelligently” removed. This allows large strings (such as shell
scripts or configuration file fragments in NixOS) to cleanly follow
the indentation of the surrounding expression. It also requires
much less escaping, since <literal>''</literal> is less common in
most languages than <literal>"</literal>.</para></listitem>
<listitem><para><command>nix-env</command> <option>--set</option>
modifies the current generation of a profile so that it contains
exactly the specified derivation, and nothing else. For example,
<literal>nix-env -p /nix/var/nix/profiles/browser --set
firefox</literal> lets the profile named
<filename>browser</filename> contain just Firefox.</para></listitem>
<listitem><para><command>nix-env</command> now maintains
meta-information about installed packages in profiles. The
meta-information is the contents of the <varname>meta</varname>
attribute of derivations, such as <varname>description</varname> or
<varname>homepage</varname>. The command <literal>nix-env -q --xml
--meta</literal> shows all meta-information.</para></listitem>
<listitem><para><command>nix-env</command> now uses the
<varname>meta.priority</varname> attribute of derivations to resolve
filename collisions between packages. Lower priority values denote
a higher priority. For instance, the GCC wrapper package and the
Binutils package in Nixpkgs both have a file
<filename>bin/ld</filename>, so previously if you tried to install
both you would get a collision. Now, on the other hand, the GCC
wrapper declares a higher priority than Binutils, so the formers
<filename>bin/ld</filename> is symlinked in the user
environment.</para></listitem>
<listitem><para><command>nix-env -i / -u</command>: instead of
breaking package ties by version, break them by priority and version
number. That is, if there are multiple packages with the same name,
then pick the package with the highest priority, and only use the
version if there are multiple packages with the same
priority.</para>
<para>This makes it possible to mark specific versions/variant in
Nixpkgs more or less desirable than others. A typical example would
be a beta version of some package (e.g.,
<literal>gcc-4.2.0rc1</literal>) which should not be installed even
though it is the highest version, except when it is explicitly
selected (e.g., <literal>nix-env -i
gcc-4.2.0rc1</literal>).</para></listitem>
<listitem><para><command>nix-env --set-flag</command> allows meta
attributes of installed packages to be modified. There are several
attributes that can be usefully modified, because they affect the
behaviour of <command>nix-env</command> or the user environment
build script:
<itemizedlist>
<listitem><para><varname>meta.priority</varname> can be changed
to resolve filename clashes (see above).</para></listitem>
<listitem><para><varname>meta.keep</varname> can be set to
<literal>true</literal> to prevent the package from being
upgraded or replaced. Useful if you want to hang on to an older
version of a package.</para></listitem>
<listitem><para><varname>meta.active</varname> can be set to
<literal>false</literal> to “disable” the package. That is, no
symlinks will be generated to the files of the package, but it
remains part of the profile (so it wont be garbage-collected).
Set it back to <literal>true</literal> to re-enable the
package.</para></listitem>
</itemizedlist>
</para></listitem>
<listitem><para><command>nix-env -q</command> now has a flag
<option>--prebuilt-only</option> (<option>-b</option>) that causes
<command>nix-env</command> to show only those derivations whose
output is already in the Nix store or that can be substituted (i.e.,
downloaded from somewhere). In other words, it shows the packages
that can be installed “quickly”, i.e., dont need to be built from
source. The <option>-b</option> flag is also available in
<command>nix-env -i</command> and <command>nix-env -u</command> to
filter out derivations for which no pre-built binary is
available.</para></listitem>
<listitem><para>The new option <option>--argstr</option> (in
<command>nix-env</command>, <command>nix-instantiate</command> and
<command>nix-build</command>) is like <option>--arg</option>, except
that the value is a string. For example, <literal>--argstr system
i686-linux</literal> is equivalent to <literal>--arg system
\"i686-linux\"</literal> (note that <option>--argstr</option>
prevents annoying quoting around shell arguments).</para></listitem>
<listitem><para><command>nix-store</command> has a new operation
<option>--read-log</option> (<option>-l</option>)
<parameter>paths</parameter> that shows the build log of the given
paths.</para></listitem>
<!--
<listitem><para>TODO: semantic cleanups of string concatenation
etc. (mostly in r6740).</para></listitem>
-->
<listitem><para>Nix now uses Berkeley DB 4.5. The database is
upgraded automatically, but you should be careful not to use old
versions of Nix that still use Berkeley DB 4.4.</para></listitem>
<!-- foo
<listitem><para>TODO: option <option>- -reregister</option> in
<command>nix-store - -register-validity</command>.</para></listitem>
-->
<listitem><para>The option <option>--max-silent-time</option>
(corresponding to the configuration setting
<literal>build-max-silent-time</literal>) allows you to set a
timeout on builds — if a build produces no output on
<literal>stdout</literal> or <literal>stderr</literal> for the given
number of seconds, it is terminated. This is useful for recovering
automatically from builds that are stuck in an infinite
loop.</para></listitem>
<listitem><para><command>nix-channel</command>: each subscribed
channel is its own attribute in the top-level expression generated
for the channel. This allows disambiguation (e.g. <literal>nix-env
-i -A nixpkgs_unstable.firefox</literal>).</para></listitem>
<listitem><para>The substitutes table has been removed from the
database. This makes operations such as <command>nix-pull</command>
and <command>nix-channel --update</command> much, much
faster.</para></listitem>
<listitem><para><command>nix-pull</command> now supports
bzip2-compressed manifests. This speeds up
channels.</para></listitem>
<listitem><para><command>nix-prefetch-url</command> now has a
limited form of caching. This is used by
<command>nix-channel</command> to prevent unnecessary downloads when
the channel hasnt changed.</para></listitem>
<listitem><para><command>nix-prefetch-url</command> now by default
computes the SHA-256 hash of the file instead of the MD5 hash. In
calls to <function>fetchurl</function> you should pass the
<literal>sha256</literal> attribute instead of
<literal>md5</literal>. You can pass either a hexadecimal or a
base-32 encoding of the hash.</para></listitem>
<listitem><para>Nix can now perform builds in an automatically
generated “chroot”. This prevents a builder from accessing stuff
outside of the Nix store, and thus helps ensure purity. This is an
experimental feature.</para></listitem>
<listitem><para>The new command <command>nix-store
--optimise</command> reduces Nix store disk space usage by finding
identical files in the store and hard-linking them to each other.
It typically reduces the size of the store by something like
25-35%.</para></listitem>
<listitem><para><filename>~/.nix-defexpr</filename> can now be a
directory, in which case the Nix expressions in that directory are
combined into an attribute set, with the file names used as the
names of the attributes. The command <command>nix-env
--import</command> (which set the
<filename>~/.nix-defexpr</filename> symlink) is
removed.</para></listitem>
<listitem><para>Derivations can specify the new special attribute
<varname>allowedReferences</varname> to enforce that the references
in the output of a derivation are a subset of a declared set of
paths. For example, if <varname>allowedReferences</varname> is an
empty list, then the output must not have any references. This is
used in NixOS to check that generated files such as initial ramdisks
for booting Linux dont have any dependencies.</para></listitem>
<listitem><para>The new attribute
<varname>exportReferencesGraph</varname> allows builders access to
the references graph of their inputs. This is used in NixOS for
tasks such as generating ISO-9660 images that contain a Nix store
populated with the closure of certain paths.</para></listitem>
<listitem><para>Fixed-output derivations (like
<function>fetchurl</function>) can define the attribute
<varname>impureEnvVars</varname> to allow external environment
variables to be passed to builders. This is used in Nixpkgs to
support proxy configuration, among other things.</para></listitem>
<listitem><para>Several new built-in functions:
<function>builtins.attrNames</function>,
<function>builtins.filterSource</function>,
<function>builtins.isAttrs</function>,
<function>builtins.isFunction</function>,
<function>builtins.listToAttrs</function>,
<function>builtins.stringLength</function>,
<function>builtins.sub</function>,
<function>builtins.substring</function>,
<function>throw</function>,
<function>builtins.trace</function>,
<function>builtins.readFile</function>.</para></listitem>
</itemizedlist>
</section>
<!--==================================================================-->
<section><title>Release 0.10.1 (October 11, 2006)</title>
<para>This release fixes two somewhat obscure bugs that occur when
evaluating Nix expressions that are stored inside the Nix store
(<literal>NIX-67</literal>). These do not affect most users.</para>
</section>
<!--==================================================================-->
<section><title>Release 0.10 (October 6, 2006)</title>

View File

@@ -46,6 +46,11 @@ h3 /* subsections */
font-size: 125%;
}
div.simplesect h2
{
font-size: 110%;
}
div.appendix h3
{
font-size: 150%;

View File

@@ -4,7 +4,9 @@
<title>Troubleshooting</title>
<para>This section provides solutions for some common problems.</para>
<para>This section provides solutions for some common problems. See
the <link xlink:href="https://bugs.cs.uu.nl/browse/NIX">Nix
bug tracker</link> for a list of currently known issues.</para>
<section><title>Berkeley DB: <quote>Cannot allocate memory</quote></title>
@@ -33,6 +35,91 @@ $ rm __db.00*</screen>
</section>
<section><title>Berkeley DB gives weird error messages</title>
<para>Symptom: you get error messages such as
<screen>
Berkeley DB message: Finding last valid log LSN: file: 1 offset 28
Berkeley DB error: file validpaths (meta pgno = 0) has LSN [483][34721].
Berkeley DB error: end of log is [1][28]
Berkeley DB error: /nix/var/nix/db/validpaths: unexpected file type or format</screen>
or other weird Berkeley DB errors, and they dont go away (i.e.,
automatic recovery doesnt work). This may be the case after a system
crash.</para>
<para>Solution: first try to run <command>db_recover</command> and
then <link linkend='refsec-nix-store-verify'><command>nix-store
--verify</command></link>:
<screen>
$ db_recover -h /nix/var/nix/db
$ nix-store --verify</screen>
(Make sure that you have the right version of
<command>db_recover</command>, namely, Berkeley DB 4.4 for Nix 0.10,
and 4.5 for Nix 0.11.)</para>
<para>If that doesnt work, its time to bring out the big guns:
<screen>
$ cd /nix/var/nix
$ cp -pr db db-backup <lineannotation>(making a backup just in case)</lineannotation>
$ cd db
$ rm __db.* log* <lineannotation>(removing the Berkeley DB environment)</lineannotation>
$ mkdir tmp
$ for i in *; do db_dump $i | (cd tmp &amp;&amp; db_load $i); done
<lineannotation>(ignore error messages about non-database files like “reserved”)</lineannotation>
$ mv tmp/* .
$ nix-store --verify</screen>
</para>
</section>
<section><title>Berkeley DB out of locks</title>
<para>It is possible, especially in <command>nix-store
--verify</command> or when running the garbage collector, to run out
of Berkeley DB locks, like this:
<screen>
$ nix-store --verify
checking path existence
checking path realisability
checking the derivers table
checking the references table
Berkeley DB error: Lock table is out of available object entries
error: Db::get: Cannot allocate memory</screen>
</para>
<para>A workaround is to increase the number of locks that Berkeley DB
allocates. (The real solution would be for Nix to not use so many
locks.) This can be done by putting the following in the file
<filename>/nix/var/nix/db/<link
xlink:href="http://www.oracle.com/technology/documentation/berkeley-db/db/ref/env/db_config.html">DB_CONFIG</link></filename>:
<programlisting>
set_lk_max_locks 100000
set_lk_max_lockers 100000
set_lk_max_objects 100000
</programlisting>
(Increase these numbers if necessary.) Then make sure that there are
no running Nix processes and delete the Berkeley DB environment:
<screen>
$ rm /nix/var/nix/db/__db.*</screen>
The Berkeley DB environment is automatically recreated with the new
limits when you run any Nix command.</para>
</section>
<section><title>Collisions in <command>nix-env</command></title>
<para>Symptom: when installing or upgrading, you get an error message such as

File diff suppressed because it is too large Load Diff

24
doc/signing.txt Normal file
View File

@@ -0,0 +1,24 @@
Generate a private key:
$ (umask 277 && openssl genrsa -out /nix/etc/nix/signing-key.sec 2048)
The private key should be kept secret (only readable to the Nix daemon
user).
Generate the corresponding public key:
$ openssl rsa -in /nix/etc/nix/signing-key.sec -pubout > /nix/etc/nix/signing-key.pub
The public key should be copied to all machines to which you want to
export store paths.
Signing:
$ nix-hash --type sha256 --flat svn.nar | openssl rsautl -sign -inkey mykey.sec > svn.nar.sign
Verifying a signature:
$ test "$(nix-hash --type sha256 --flat svn.nar)" = "$(openssl rsautl -verify -inkey mykey.pub -pubin -in svn.nar.sign)"

30
externals/Makefile.am vendored
View File

@@ -1,11 +1,11 @@
# Berkeley DB
DB = db-4.4.20.NC
DB = db-4.5.20
$(DB).tar.gz:
@echo "Nix requires Berkeley DB to build."
@echo "Please download version 4.4.20 from"
@echo " http://downloads.sleepycat.com/db-4.4.20.NC.tar.gz"
@echo "Please download version 4.5.20 from"
@echo " http://download-east.oracle.com/berkeley-db/db-4.5.20.tar.gz"
@echo "and place it in the externals/ directory."
false
@@ -35,19 +35,17 @@ endif
# CWI ATerm
ATERM = aterm-2.4.2
ATERM = aterm-2.4.2-fixes-r2
$(ATERM).tar.gz:
$(ATERM).tar.bz2:
@echo "Nix requires the CWI ATerm library to build."
@echo "Please download version 2.4.2 from"
@echo " http://www.cwi.nl/projects/MetaEnv/aterm/aterm-2.4.2.tar.gz"
@echo "Please download version 2.4.2-fixes-r2 from"
@echo " http://losser.st-lab.cs.uu.nl/~eelco/dist/aterm-2.4.2-fixes-r2.tar.bz2"
@echo "and place it in the externals/ directory."
false
$(ATERM): $(ATERM).tar.gz
gunzip < $(srcdir)/$(ATERM).tar.gz | tar xvf -
(cd $(ATERM) && $(patch) -p1) < $(srcdir)/aterm-aliasing.patch
# (cd $(ATERM) && $(patch) -p1) < $(srcdir)/aterm-64-bit.patch
$(ATERM): $(ATERM).tar.bz2
bunzip2 < $(srcdir)/$(ATERM).tar.bz2 | tar xvf -
have-aterm:
$(MAKE) $(ATERM)
@@ -69,12 +67,12 @@ endif
# bzip2
BZIP2 = bzip2-1.0.3
BZIP2 = bzip2-1.0.4
$(BZIP2).tar.gz:
@echo "Nix requires bzip2 to build."
@echo "Please download version 1.0.3 from"
@echo " http://www.bzip.org/1.0.3/bzip2-1.0.3.tar.gz"
@echo "Please download version 1.0.4 from"
@echo " http://www.bzip.org/1.0.4/bzip2-1.0.4.tar.gz"
@echo "and place it in the externals/ directory."
false
@@ -103,8 +101,8 @@ endif
all: build-db build-aterm build-bzip2
EXTRA_DIST = $(DB).tar.gz $(ATERM).tar.gz $(BZIP2).tar.gz \
bdb-cygwin.patch aterm-aliasing.patch aterm-64-bit.patch
EXTRA_DIST = $(DB).tar.gz $(ATERM).tar.bz2 $(BZIP2).tar.gz \
bdb-cygwin.patch
ext-clean:
$(RM) -f have-db build-db have-aterm build-aterm

View File

@@ -1,661 +0,0 @@
diff -rc aterm-2.4.2-orig/aterm/bafio.c aterm-2.4.2/aterm/bafio.c
*** aterm-2.4.2-orig/aterm/bafio.c 2004-02-02 12:24:34.000000000 +0100
--- aterm-2.4.2/aterm/bafio.c 2006-09-22 13:39:07.000000000 +0200
***************
*** 222,227 ****
--- 222,229 ----
}
}
+ if (val) return -1;
+
/* Ok */
return 0;
}
***************
*** 544,551 ****
* terms have been sorted by symbol.
*/
! void gather_top_symbols(sym_entry *cur_entry, int cur_arg,
! int total_top_symbols)
{
int index;
unsigned int hnr;
--- 546,553 ----
* terms have been sorted by symbol.
*/
! static void gather_top_symbols(sym_entry *cur_entry, int cur_arg,
! int total_top_symbols)
{
int index;
unsigned int hnr;
***************
*** 899,905 ****
} else {
switch(ATgetType(t)) {
case AT_INT:
! if(writeBits(ATgetInt((ATermInt)t), HEADER_BITS, writer) < 0) {
return ATfalse;
}
#if 0
--- 901,908 ----
} else {
switch(ATgetType(t)) {
case AT_INT:
! /* If ATerm integers are > 32 bits, then this can fail. */
! if(writeBits(ATgetInt((ATermInt)t), INT_SIZE_IN_BAF, writer) < 0) {
return ATfalse;
}
#if 0
***************
*** 1033,1039 ****
/*}}} */
/*{{{ ATbool write_baf(ATerm t, byte_writer *writer) */
! ATbool
write_baf(ATerm t, byte_writer *writer)
{
int nr_unique_terms = 0;
--- 1036,1042 ----
/*}}} */
/*{{{ ATbool write_baf(ATerm t, byte_writer *writer) */
! static ATbool
write_baf(ATerm t, byte_writer *writer)
{
int nr_unique_terms = 0;
***************
*** 1233,1239 ****
* Read a single symbol from file.
*/
! Symbol read_symbol(byte_reader *reader)
{
unsigned int arity, quoted;
int len;
--- 1236,1242 ----
* Read a single symbol from file.
*/
! static Symbol read_symbol(byte_reader *reader)
{
unsigned int arity, quoted;
int len;
***************
*** 1260,1266 ****
* Read all symbols from file.
*/
! ATbool read_all_symbols(byte_reader *reader)
{
unsigned int val;
int i, j, k, arity;
--- 1263,1269 ----
* Read all symbols from file.
*/
! static ATbool read_all_symbols(byte_reader *reader)
{
unsigned int val;
int i, j, k, arity;
***************
*** 1280,1293 ****
/*}}} */
/*{{{ Read term count and allocate space */
! if(readInt(&val, reader) < 0)
return ATfalse;
read_symbols[i].nr_terms = val;
read_symbols[i].term_width = bit_width(val);
! if(val == 0)
! read_symbols[i].terms = NULL;
! else
! read_symbols[i].terms = (ATerm *)calloc(val, sizeof(ATerm));
if(!read_symbols[i].terms)
ATerror("read_symbols: could not allocate space for %d terms.\n", val);
ATprotectArray(read_symbols[i].terms, val);
--- 1283,1293 ----
/*}}} */
/*{{{ Read term count and allocate space */
! if(readInt(&val, reader) < 0 || val == 0)
return ATfalse;
read_symbols[i].nr_terms = val;
read_symbols[i].term_width = bit_width(val);
! read_symbols[i].terms = (ATerm *)calloc(val, sizeof(ATerm));
if(!read_symbols[i].terms)
ATerror("read_symbols: could not allocate space for %d terms.\n", val);
ATprotectArray(read_symbols[i].terms, val);
***************
*** 1351,1357 ****
/*}}} */
/*{{{ ATerm read_term(sym_read_entry *sym, byte_reader *reader) */
! ATerm read_term(sym_read_entry *sym, byte_reader *reader)
{
unsigned int val;
int i, arity = sym->arity;
--- 1351,1357 ----
/*}}} */
/*{{{ ATerm read_term(sym_read_entry *sym, byte_reader *reader) */
! static ATerm read_term(sym_read_entry *sym, byte_reader *reader)
{
unsigned int val;
int i, arity = sym->arity;
***************
*** 1365,1370 ****
--- 1365,1371 ----
ATprotectArray(args, arity);
if(!args)
ATerror("could not allocate space for %d arguments.\n", arity);
+ /* !!! leaks memory on the "return NULL" paths */
}
/*ATfprintf(stderr, "reading term over symbol %y\n", sym->sym);*/
***************
*** 1372,1377 ****
--- 1373,1380 ----
/*ATfprintf(stderr, " reading argument %d (%d)", i, sym->sym_width[i]);*/
if(readBits(&val, sym->sym_width[i], reader) < 0)
return NULL;
+ if(val >= sym->nr_topsyms[i])
+ return NULL;
arg_sym = &read_symbols[sym->topsyms[i][val]];
/* ATfprintf(stderr, "argument %d, symbol index = %d, symbol = %y\n",
i, val, arg_sym->sym);*/
***************
*** 1381,1386 ****
--- 1384,1391 ----
if(readBits(&val, arg_sym->term_width, reader) < 0)
return NULL;
/* ATfprintf(stderr, "arg term index = %d\n", val);*/
+ if(val >= arg_sym->nr_terms)
+ return NULL;
if(!arg_sym->terms[val]) {
arg_sym->terms[val] = read_term(arg_sym, reader);
if(!arg_sym->terms[val])
***************
*** 1396,1402 ****
case AS_INT:
/*{{{ Read an integer */
! if(readBits(&val, HEADER_BITS, reader) < 0)
return NULL;
result = (ATerm)ATmakeInt((int)val);
--- 1401,1407 ----
case AS_INT:
/*{{{ Read an integer */
! if(readBits(&val, INT_SIZE_IN_BAF, reader) < 0)
return NULL;
result = (ATerm)ATmakeInt((int)val);
***************
*** 1494,1502 ****
for(i=0; i<nr_unique_symbols; i++) {
sym_read_entry *entry = &read_symbols[i];
! ATunprotectArray(entry->terms);
! if(entry->terms)
free(entry->terms);
if(entry->nr_topsyms)
free(entry->nr_topsyms);
if(entry->sym_width)
--- 1499,1508 ----
for(i=0; i<nr_unique_symbols; i++) {
sym_read_entry *entry = &read_symbols[i];
! if(entry->terms) {
! ATunprotectArray(entry->terms);
free(entry->terms);
+ }
if(entry->nr_topsyms)
free(entry->nr_topsyms);
if(entry->sym_width)
Only in aterm-2.4.2/aterm: config.h.in
diff -rc aterm-2.4.2-orig/aterm/encoding.h aterm-2.4.2/aterm/encoding.h
*** aterm-2.4.2-orig/aterm/encoding.h 2004-06-01 10:29:02.000000000 +0200
--- aterm-2.4.2/aterm/encoding.h 2006-09-22 13:39:07.000000000 +0200
***************
*** 10,15 ****
--- 10,17 ----
{
#endif/* __cplusplus */
+ #include "config.h"
+
/*
|--------------------------------|
|info|type |arity|quoted|mark|age|
***************
*** 31,37 ****
#define SHIFT_REMOVE_MARK_AGE 3
#define MASK_AGE_MARK (MASK_AGE|MASK_MARK)
! #if AT_64BIT
#define SHIFT_LENGTH 34
#define HEADER_BITS 64
typedef unsigned long header_type;
--- 33,39 ----
#define SHIFT_REMOVE_MARK_AGE 3
#define MASK_AGE_MARK (MASK_AGE|MASK_MARK)
! #ifdef AT_64BIT
#define SHIFT_LENGTH 34
#define HEADER_BITS 64
typedef unsigned long header_type;
***************
*** 137,142 ****
--- 139,150 ----
#define AT_TABLE_SIZE(table_class) (1<<(table_class))
#define AT_TABLE_MASK(table_class) (AT_TABLE_SIZE(table_class)-1)
+
+ /* Integers in BAF are always exactly 32 bits. The size must be fixed so that
+ * BAF terms can be exchanged between platforms. */
+ #define INT_SIZE_IN_BAF 32
+
+
#ifdef __cplusplus
}
#endif/* __cplusplus */
diff -rc aterm-2.4.2-orig/aterm/gc.c aterm-2.4.2/aterm/gc.c
*** aterm-2.4.2-orig/aterm/gc.c 2004-06-01 10:29:02.000000000 +0200
--- aterm-2.4.2/aterm/gc.c 2006-09-22 13:39:07.000000000 +0200
***************
*** 154,166 ****
}
#ifdef AT_64BIT
! odd_term = *((ATerm *)((MachineWord)cur)+4);
real_term = AT_isInsideValidTerm(odd_term);
if (real_term != NULL) {
AT_markTerm(odd_term);
}
! odd_sym = *((AFun *)((MachineWord)cur)+4);
if (AT_isValidSymbol(odd_sym)) {
/*fprintf(stderr,"mark_memory: AT_markSymbol(%d)\n",odd_sym);*/
AT_markSymbol(odd_sym);
--- 154,166 ----
}
#ifdef AT_64BIT
! odd_term = *((ATerm *)(((MachineWord)cur)+4));
real_term = AT_isInsideValidTerm(odd_term);
if (real_term != NULL) {
AT_markTerm(odd_term);
}
! odd_sym = *((AFun *)(((MachineWord)cur)+4));
if (AT_isValidSymbol(odd_sym)) {
/*fprintf(stderr,"mark_memory: AT_markSymbol(%d)\n",odd_sym);*/
AT_markSymbol(odd_sym);
***************
*** 198,210 ****
}
#ifdef AT_64BIT
! odd_term = *((ATerm *)((MachineWord)cur)+4);
real_term = AT_isInsideValidTerm(odd_term);
if (real_term != NULL) {
AT_markTerm_young(odd_term);
}
! odd_sym = *((AFun *)((MachineWord)cur)+4);
if (AT_isValidSymbol(odd_sym)) {
/*fprintf(stderr,"mark_memory_young: AT_markSymbol_young(%d)\n",odd_sym);*/
AT_markSymbol_young(odd_sym);
--- 198,210 ----
}
#ifdef AT_64BIT
! odd_term = *((ATerm *)(((MachineWord)cur)+4));
real_term = AT_isInsideValidTerm(odd_term);
if (real_term != NULL) {
AT_markTerm_young(odd_term);
}
! odd_sym = *((AFun *)(((MachineWord)cur)+4));
if (AT_isValidSymbol(odd_sym)) {
/*fprintf(stderr,"mark_memory_young: AT_markSymbol_young(%d)\n",odd_sym);*/
AT_markSymbol_young(odd_sym);
***************
*** 225,235 ****
ATerm *start, *stop;
ProtEntry *prot;
- #ifdef AT_64BIT
- ATerm oddTerm;
- AFun oddSym;
- #endif
-
#ifdef WIN32
unsigned int r_eax, r_ebx, r_ecx, r_edx, \
--- 225,230 ----
***************
*** 287,293 ****
/* Traverse possible register variables */
sigsetjmp(env,0);
! start = (ATerm *)env;
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
mark_memory(start, stop);
#endif
--- 282,288 ----
/* Traverse possible register variables */
sigsetjmp(env,0);
! start = (ATerm *)env; /* !!! illegal aliasing */
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
mark_memory(start, stop);
#endif
***************
*** 338,348 ****
ATerm *start, *stop;
ProtEntry *prot;
- #ifdef AT_64BIT
- ATerm oddTerm;
- AFun oddSym;
- #endif
-
#ifdef WIN32
unsigned int r_eax, r_ebx, r_ecx, r_edx, \
--- 333,338 ----
***************
*** 400,406 ****
/* Traverse possible register variables */
sigsetjmp(env,0);
! start = (ATerm *)env;
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
mark_memory_young(start, stop);
#endif
--- 390,396 ----
/* Traverse possible register variables */
sigsetjmp(env,0);
! start = (ATerm *)env; /* !!! illegal aliasing */
stop = ((ATerm *)(((char *)env) + sizeof(sigjmp_buf)));
mark_memory_young(start, stop);
#endif
***************
*** 1047,1053 ****
/*fprintf(stderr,"minor_sweep_phase_young: ensure empty freelist[%d]\n",size);*/
for(data = at_freelist[size] ; data ; data=data->next) {
if(!EQUAL_HEADER(data->header,FREE_HEADER)) {
! fprintf(stderr,"data = %x header = %x\n",(unsigned int)data,data->header);
}
assert(EQUAL_HEADER(data->header,FREE_HEADER));
assert(ATgetType(data) == AT_FREE);
--- 1037,1043 ----
/*fprintf(stderr,"minor_sweep_phase_young: ensure empty freelist[%d]\n",size);*/
for(data = at_freelist[size] ; data ; data=data->next) {
if(!EQUAL_HEADER(data->header,FREE_HEADER)) {
! fprintf(stderr,"data = %p header = %x\n",data,(unsigned int) data->header);
}
assert(EQUAL_HEADER(data->header,FREE_HEADER));
assert(ATgetType(data) == AT_FREE);
diff -rc aterm-2.4.2-orig/aterm/Makefile.am aterm-2.4.2/aterm/Makefile.am
*** aterm-2.4.2-orig/aterm/Makefile.am 2005-08-03 11:45:19.000000000 +0200
--- aterm-2.4.2/aterm/Makefile.am 2006-09-22 13:39:07.000000000 +0200
***************
*** 37,43 ****
aterm2.h \
atypes.h \
deprecated.h \
! encoding.h
PRIVATE_INCL = \
_afun.h \
--- 37,44 ----
aterm2.h \
atypes.h \
deprecated.h \
! encoding.h \
! config.h
PRIVATE_INCL = \
_afun.h \
diff -rc aterm-2.4.2-orig/aterm/md5.h aterm-2.4.2/aterm/md5.h
*** aterm-2.4.2-orig/aterm/md5.h 2003-09-02 15:32:46.000000000 +0200
--- aterm-2.4.2/aterm/md5.h 2006-09-22 13:39:07.000000000 +0200
***************
*** 24,29 ****
--- 24,31 ----
documentation and/or software.
*/
+ #include <stdint.h>
+
/* GLOBAL.H - RSAREF types and constants
*/
***************
*** 46,55 ****
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
! typedef unsigned short int UINT2;
/* UINT4 defines a four byte word */
! typedef unsigned long int UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
--- 48,57 ----
typedef unsigned char *POINTER;
/* UINT2 defines a two byte word */
! typedef uint16_t UINT2;
/* UINT4 defines a four byte word */
! typedef uint32_t UINT4;
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
diff -rc aterm-2.4.2-orig/aterm/memory.c aterm-2.4.2/aterm/memory.c
*** aterm-2.4.2-orig/aterm/memory.c 2005-10-11 13:19:25.000000000 +0200
--- aterm-2.4.2/aterm/memory.c 2006-09-22 13:39:16.000000000 +0200
***************
*** 96,102 ****
#define HASHNUMBER4(t) hash_number(t,4)
#define HASHINT(val) (tmp[0]=(MachineWord)(AT_INT<<SHIFT_TYPE),\
tmp[1]=(MachineWord)0,\
! tmp[2]=(MachineWord)val,\
hash_number(tmp,3))
#else
--- 96,102 ----
#define HASHNUMBER4(t) hash_number(t,4)
#define HASHINT(val) (tmp[0]=(MachineWord)(AT_INT<<SHIFT_TYPE),\
tmp[1]=(MachineWord)0,\
! tmp[2]=(MachineWord)((unsigned int) val),\
hash_number(tmp,3))
#else
***************
*** 127,133 ****
((MachineWord*)t)[2]),((MachineWord*)t)[3]))
#define HASHINT(val) \
! FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
#endif /* HASHPEM */
--- 127,133 ----
((MachineWord*)t)[2]),((MachineWord*)t)[3]))
#define HASHINT(val) \
! FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), (unsigned int) val))
#endif /* HASHPEM */
***************
*** 708,714 ****
at_blocks[size] = newblock;
top_at_blocks[size] = newblock->data;
assert(at_blocks[size] != NULL);
! assert(((int)top_at_blocks[size] % MAX(sizeof(double), sizeof(void *))) == 0);
/* [pem: Feb 14 02] TODO: fast allocation */
assert(at_freelist[size] == NULL);
--- 708,714 ----
at_blocks[size] = newblock;
top_at_blocks[size] = newblock->data;
assert(at_blocks[size] != NULL);
! assert(((long)top_at_blocks[size] % MAX(sizeof(double), sizeof(void *))) == 0);
/* [pem: Feb 14 02] TODO: fast allocation */
assert(at_freelist[size] == NULL);
***************
*** 1009,1018 ****
do {
if(!cur) {
/*printf("freeterm = %d\n",t);*/
! fprintf(stderr,"### cannot find term %x in hashtable at pos %d header = %x\n", (unsigned int)t, hnr, t->header);
!
! ATabort("### cannot find term %n at %p in hashtable at pos %d"
! ", header = %d\n", t, t, hnr, t->header);
}
if (cur == t) {
if(prev)
--- 1009,1016 ----
do {
if(!cur) {
/*printf("freeterm = %d\n",t);*/
! ATabort("### cannot find term %p in hashtable at pos %d"
! ", header = %x\n", t, hnr, t->header);
}
if (cur == t) {
if(prev)
***************
*** 1728,1733 ****
--- 1726,1733 ----
hashtable[hnr] = cur;
}
+ assert((hnr & table_mask) == (hash_number(cur, TERM_SIZE_INT) & table_mask));
+
return (ATermInt)cur;
}
diff -rc aterm-2.4.2-orig/aterm.m4 aterm-2.4.2/aterm.m4
*** aterm-2.4.2-orig/aterm.m4 2005-08-03 11:45:19.000000000 +0200
--- aterm-2.4.2/aterm.m4 2006-09-22 13:39:07.000000000 +0200
***************
*** 8,15 ****
[AS_HELP_STRING([--with-sharing],[create libraries that do term sharing @<:@yes@:>@])],
[if test "$withval" = "no"; then
AC_MSG_RESULT([no])
! AC_DEFINE([NO_SHARING])
! AC_DEFINE([WITH_STATS])
else
if test "$withval" != "yes"; then
AC_MSG_RESULT([unknown value specified for --with-sharing.])
--- 8,15 ----
[AS_HELP_STRING([--with-sharing],[create libraries that do term sharing @<:@yes@:>@])],
[if test "$withval" = "no"; then
AC_MSG_RESULT([no])
! AC_DEFINE([NO_SHARING], [], [Whether terms are shared.])
! AC_DEFINE([WITH_STATS], [], [Whether to keep statistics.])
else
if test "$withval" != "yes"; then
AC_MSG_RESULT([unknown value specified for --with-sharing.])
***************
*** 73,78 ****
--- 73,102 ----
AC_SUBST([OPTIMIZECFLAGS])
])
+ # ATERM_64_BIT
+ # ------------
+ # Enable 64-bit mode if pointers are 8 bytes large.
+ AC_DEFUN([ATERM_64_BIT], [
+ AC_CHECK_SIZEOF(void *)
+ AC_CHECK_SIZEOF(int)
+ AC_CHECK_SIZEOF(long)
+
+ AC_MSG_CHECKING([what kind of platform this is])
+
+ AC_SUBST([AT_64BIT], [0])
+ if test "$ac_cv_sizeof_void_p" = "8" -a "$ac_cv_sizeof_int" = "4" -a "$ac_cv_sizeof_long" = "8"; then
+ AC_MSG_RESULT([LP64])
+ AC_SUBST([AT_64BIT], [1])
+ elif test "$ac_cv_sizeof_void_p" = "8" -a "$ac_cv_sizeof_int" = "8" -a "$ac_cv_sizeof_long" = "8"; then
+ AC_MSG_RESULT([ILP64 - warning, untested])
+ AC_SUBST([AT_64BIT], [1])
+ elif test "$ac_cv_sizeof_void_p" = "4" -a "$ac_cv_sizeof_int" = "4" -a "$ac_cv_sizeof_long" = "4"; then
+ AC_MSG_RESULT([32 bits])
+ else
+ AC_MSG_RESULT([something weird - warning, untested])
+ fi
+ ])
+
# XT_SVN_REVISION
# ---------------
AC_DEFUN([XT_SVN_REVISION],
diff -rc aterm-2.4.2-orig/configure.ac aterm-2.4.2/configure.ac
*** aterm-2.4.2-orig/configure.ac 2005-08-03 11:45:19.000000000 +0200
--- aterm-2.4.2/configure.ac 2006-09-22 13:39:07.000000000 +0200
***************
*** 30,35 ****
--- 30,38 ----
# Add a configuration option to allow users to control sharing.
ATERM_WITH_SHARING
+ # Enable 64-bit mode if pointers are 8 bytes large.
+ ATERM_64_BIT
+
CURDATE=`date`
AC_SUBST([CURDATE])
***************
*** 45,49 ****
--- 48,53 ----
doc/spec/Makefile
aterm.spec
aterm.pc
+ aterm/config.h
])
AC_OUTPUT
diff -rc aterm-2.4.2-orig/utils/dicttoc.c aterm-2.4.2/utils/dicttoc.c
*** aterm-2.4.2-orig/utils/dicttoc.c 2003-10-07 13:57:40.000000000 +0200
--- aterm-2.4.2/utils/dicttoc.c 2006-09-22 13:39:07.000000000 +0200
***************
*** 69,74 ****
--- 69,75 ----
fprintf(file, "#ifndef __%s_H\n", code_prefix);
fprintf(file, "#define __%s_H\n\n", code_prefix);
fprintf(file, "#include <aterm2.h>\n\n");
+ fprintf(file, "#include <assert.h>\n\n");
while (!ATisEmpty(afuns)) {
ATerm afun, alias, pair = ATgetFirst(afuns);
***************
*** 244,251 ****
ATfprintf(file, "{\n");
ATfprintf(file, " ATermList afuns, terms;\n\n");
! ATfprintf(file, " _%s = ATreadFromBinaryString(_%s_baf, _%s_LEN);\n\n",
code_prefix, code_prefix, code_prefix);
ATfprintf(file, " ATprotect(&_%s);\n\n", code_prefix);
ATfprintf(file, " afuns = (ATermList)ATelementAt((ATermList)_%s, 0);\n\n", code_prefix);
--- 245,253 ----
ATfprintf(file, "{\n");
ATfprintf(file, " ATermList afuns, terms;\n\n");
! ATfprintf(file, " _%s = ATreadFromBinaryString(_%s_baf, _%s_LEN);\n",
code_prefix, code_prefix, code_prefix);
+ ATfprintf(file, " assert(_%s);\n\n", code_prefix);
ATfprintf(file, " ATprotect(&_%s);\n\n", code_prefix);
ATfprintf(file, " afuns = (ATermList)ATelementAt((ATermList)_%s, 0);\n\n", code_prefix);

View File

@@ -1,224 +0,0 @@
diff -rc aterm-1142707243.10633/aterm/aterm.c aterm/aterm/aterm.c
*** aterm-1142707243.10633/aterm/aterm.c 2006-02-08 11:35:28.000000000 +0100
--- aterm/aterm/aterm.c 2006-04-25 17:10:52.000000000 +0200
***************
*** 193,198 ****
--- 193,199 ----
/* that have char == 2 bytes, and sizeof(header_type) == 2 */
assert(sizeof(header_type) == sizeof(ATerm *));
assert(sizeof(header_type) >= 4);
+ assert(sizeof(ATerm) == sizeof(MachineWord));
/*}}} */
/*{{{ Initialize buffer */
diff -rc aterm-1142707243.10633/aterm/memory.c aterm/aterm/memory.c
*** aterm-1142707243.10633/aterm/memory.c 2006-03-09 15:02:56.000000000 +0100
--- aterm/aterm/memory.c 2006-04-25 18:22:00.000000000 +0200
***************
*** 119,130 ****
hash_number(tmp,3))
*/
#define HASHNUMBER3(t)\
! FINISH(COMBINE(START(((MachineWord*)t)[0]), ((MachineWord*)t)[2]))
#define HASHNUMBER4(t)\
! FINISH(COMBINE(COMBINE(START(((MachineWord*)t)[0]), \
! ((MachineWord*)t)[2]),((MachineWord*)t)[3]))
#define HASHINT(val) \
FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
--- 119,171 ----
hash_number(tmp,3))
*/
+ /* The ATerm library use some heavy aliasing. For instance, the
+ various ATermXXX structures are referenced through MachineWord
+ arrays. This is not generally allowed by the C standard --- see
+ C99, section 6.5, clause 7. In particular, this means that you
+ cannot assign something through an ATermXXX pointer, e.g.,
+
+ protoAppl->header = header;
+
+ and then read it through a MachineWord*, e.g.,
+
+ hnr = hash_number((ATerm) protoAppl, 2);
+
+ (hash_number walks over the term by casting it to a MachineWord*).
+
+ However, the same clause of the C standard also specifies that you
+ *can* read the memory location through a union type that contains
+ both the original type (e.g. ATermAppl) and the type used to read
+ the memory location (e.g. MachineWord). That's what we do
+ below: we have a union of all the types that occur in the various
+ ATerm types. We then read the "w" element of the union. The
+ compiler is not allowed to assume absence of aliasing with the
+ other types in the union.
+
+ A better solution would be to hash the term through a character
+ pointer (since *any* memory location can be legally read as a
+ character), but I'm too lazy right now. Performance might also
+ suffer if we do that. */
+
+ typedef union
+ {
+ MachineWord w;
+ header_type header;
+ ATerm term;
+ ATermList list;
+ int i;
+ double d;
+ void* p;
+ } Aliaser;
+
+ #define GET_WORD(t, n) (((Aliaser*) (((MachineWord*) t) + n))->w)
+
#define HASHNUMBER3(t)\
! FINISH(COMBINE(START(GET_WORD(t, 0)), GET_WORD(t, 2)))
#define HASHNUMBER4(t)\
! FINISH(COMBINE(COMBINE(START(GET_WORD(t, 0)), \
! GET_WORD(t, 2)), GET_WORD(t, 3)))
#define HASHINT(val) \
FINISH(COMBINE(START( (AT_INT<<SHIFT_TYPE) ), val))
***************
*** 132,144 ****
#endif /* HASHPEM */
! #define PROTO_APPL_ARGS ((ATerm *) (protoTerm + ARG_OFFSET))
#define SET_PROTO_APPL_ARG(i, a) \
! (PROTO_APPL_ARGS[(i)] = (a))
#define GET_PROTO_APPL_ARG(i) \
! (PROTO_APPL_ARGS[(i)])
#define CHECK_TERM(t) \
assert((t) != NULL \
--- 173,185 ----
#endif /* HASHPEM */
! #define PROTO_APPL_ARGS (protoTerm + ARG_OFFSET)
#define SET_PROTO_APPL_ARG(i, a) \
! (PROTO_APPL_ARGS[(i)] = (MachineWord) (a))
#define GET_PROTO_APPL_ARG(i) \
! ((ATerm) PROTO_APPL_ARGS[(i)])
#define CHECK_TERM(t) \
assert((t) != NULL \
***************
*** 323,336 ****
#else
static HashNumber hash_number(ATerm t, int size)
{
- MachineWord *words = (MachineWord *) t;
int i;
HashNumber hnr;
! hnr = START(HIDE_AGE_MARK(words[0]));
for (i=2; i<size; i++) {
! hnr = COMBINE(hnr, words[i]);
}
return FINISH(hnr);
--- 364,376 ----
#else
static HashNumber hash_number(ATerm t, int size)
{
int i;
HashNumber hnr;
! hnr = START(HIDE_AGE_MARK(GET_WORD(t, 0)));
for (i=2; i<size; i++) {
! hnr = COMBINE(hnr, GET_WORD(t, i));
}
return FINISH(hnr);
***************
*** 338,351 ****
static HashNumber hash_number_anno(ATerm t, int size, ATerm anno)
{
- MachineWord *words = (MachineWord *) t;
int i;
HashNumber hnr;
! hnr = START(HIDE_AGE_MARK(words[0]));
for (i=2; i<size; i++) {
! hnr = COMBINE(hnr, words[i]);
}
hnr = COMBINE(hnr, (MachineWord)anno);
--- 378,390 ----
static HashNumber hash_number_anno(ATerm t, int size, ATerm anno)
{
int i;
HashNumber hnr;
! hnr = START(HIDE_AGE_MARK(GET_WORD(t, 0)));
for (i=2; i<size; i++) {
! hnr = COMBINE(hnr, GET_WORD(t, i));
}
hnr = COMBINE(hnr, (MachineWord)anno);
***************
*** 1639,1645 ****
protoAppl->header = header;
CHECK_HEADER(protoAppl->header);
! if (args != PROTO_APPL_ARGS) {
for (i=0; i<arity; i++) {
CHECK_TERM(args[i]);
SET_PROTO_APPL_ARG(i, args[i]);
--- 1678,1684 ----
protoAppl->header = header;
CHECK_HEADER(protoAppl->header);
! if (args != (ATerm *) PROTO_APPL_ARGS) {
for (i=0; i<arity; i++) {
CHECK_TERM(args[i]);
SET_PROTO_APPL_ARG(i, args[i]);
***************
*** 1680,1686 ****
hashtable[hnr] = cur;
}
! if (args != PROTO_APPL_ARGS) {
for (i=0; i<arity; i++) {
protected_buffer[i] = NULL;
}
--- 1719,1725 ----
hashtable[hnr] = cur;
}
! if (args != (ATerm *) PROTO_APPL_ARGS) {
for (i=0; i<arity; i++) {
protected_buffer[i] = NULL;
}
***************
*** 2144,2150 ****
}
SET_PROTO_APPL_ARG(n, arg);
! result = ATmakeApplArray(sym, PROTO_APPL_ARGS);
annos = AT_getAnnotations((ATerm)appl);
if (annos != NULL) {
result = (ATermAppl)AT_setAnnotations((ATerm)result, annos);
--- 2183,2189 ----
}
SET_PROTO_APPL_ARG(n, arg);
! result = ATmakeApplArray(sym, (ATerm *) PROTO_APPL_ARGS);
annos = AT_getAnnotations((ATerm)appl);
if (annos != NULL) {
result = (ATermAppl)AT_setAnnotations((ATerm)result, annos);

View File

@@ -1,21 +1,22 @@
diff -rc db-4.4.20.NC-old/os/os_flock.c db-4.4.20.NC/os/os_flock.c
*** db-4.4.20.NC-old/os/os_flock.c Mon Jun 20 16:59:01 2005
--- db-4.4.20.NC/os/os_flock.c Wed Jun 7 17:01:49 2006
diff -rc db-4.5.20-orig/os/os_flock.c db-4.5.20/os/os_flock.c
*** db-4.5.20-orig/os/os_flock.c 2006-10-13 12:36:12.000000000 +0200
--- db-4.5.20/os/os_flock.c 2006-10-13 12:40:11.000000000 +0200
***************
*** 36,41 ****
--- 36,50 ----
*** 30,35 ****
--- 30,44 ----
DB_ASSERT(F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
DB_ASSERT(dbenv, F_ISSET(fhp, DB_FH_OPENED) && fhp->fd != -1);
+ #ifdef __CYGWIN__
+ /*
+ * Windows file locking interferes with read/write operations, so we
+ * map the ranges to an area past the end of the file.
+ */
+ DB_ASSERT(offset < (off_t) 1 << 62);
+ DB_ASSERT(dbenv, offset < (off_t) 1 << 62);
+ offset += (off_t) 1 << 62;
+ #endif
+
#ifdef HAVE_FCNTL
fl.l_start = offset;
fl.l_len = 1;
fl.l_type = acquire ? F_WRLCK : F_UNLCK;
Only in db-4.5.20/os: os_flock.c~

67
install_full.sh Executable file
View File

@@ -0,0 +1,67 @@
#! /bin/sh -e
make clean # comment this out when needed !!!
export nixstatepath=/nixstate2/nix
export ACLOCAL_PATH=/home/wouterdb/.nix-profile/share/aclocal
if [ "$1" = "full" ]; then
nix-env-all-pkgs.sh -i gcc
nix-env-all-pkgs.sh -i gnum4
nix-env-all-pkgs.sh -i autoconf
nix-env-all-pkgs.sh -i automake
nix-env-all-pkgs.sh -i gnused
nix-env-all-pkgs.sh -i db4
nix-env-all-pkgs.sh -i aterm
nix-env-all-pkgs.sh -i bzip2
nix-env-all-pkgs.sh -i flex
nix-env-all-pkgs.sh -i bsdiff
nix-env-all-pkgs.sh -i libtool
nix-env-all-pkgs.sh -i docbook5
nix-env-all-pkgs.sh -i docbook5-xsl
nix-env-all-pkgs.sh -i bison
nix-env-all-pkgs.sh -i gdb #optional for debugging
nix-env-all-pkgs.sh -i gnupatch
nix-env-all-pkgs.sh -i gnumake
nix-env-all-pkgs.sh -i ext3cow-tools
nix-env-all-pkgs.sh -i e3cfsprogs
nix-env-all-pkgs.sh -i rsync
fi
if [ "$1" = "full" ] || [ "$1" = "auto" ]; then
export AUTOCONF=autoconf
export AUTOHEADER=autoheader
export AUTOMAKE=automake
autoconf
autoreconf -f
aclocal
autoheader
automake
fi
./bootstrap.sh
./configure --with-aterm=$HOME/.nix-profile \
--with-bzip2=$HOME/.nix-profile \
--with-bdb=$HOME/.nix-profile \
--with-docbook-xsl=$HOME/.nix-profile \
--with-docbook-rng=/home/wouterdb/.nix-profile/xml/rng/docbook \
--with-docbook-xsl=/home/wouterdb/.nix-profile/xml/xsl/docbook \
--prefix=$nixstatepath \
--with-store-dir=/nix/store \
--with-store-state-dir=/nix/state \
--with-ext3cow-header=/nix/store/2sm0h2xd1zsm5had53q1pvzmnsn8fy8k-linux-2.6.21/lib/modules/2.6.21-ck1-default/build/include/linux/ext3cow_fs.h \
--localstatedir=/nix/var
#Options from the nix expr
#--disable-init-state
#--with-store-dir=/nix/store
#--localstatedir=/nix/var
#--with-aterm=/nix/store/pkmzbb613wa8cwngx8jjb5jaic8yhyzs-aterm-2.4.2-fixes
#--with-bdb=/nix/store/4yv4j1cd7i5j3mhs5wpc1kzlz1cj8n82-db4-4.5.20
#--with-bzip2=/nix/store/dh0mdgkvhv3pwrf8zp58phpzn9rcm49r-bzip2-1.0.3
#--disable-init-state
echo "New state nix version by wouter ..." > doc/manual/NEWS.txt
make

16
install_install_d.sh Executable file
View File

@@ -0,0 +1,16 @@
#! /bin/sh -e
if [ $(whoami) = "root" ]
then
su - wouterdb -c "cd /home/wouterdb/dev/nix-state/; make"
make install
chown -R wouterdb.wouterdb /nixstate2/nix/
./restartDaemon.sh
else
echo "You must be ROOT to run this script."
exit 0
fi

5
install_make.sh Executable file
View File

@@ -0,0 +1,5 @@
#! /bin/sh -e
make

36
mergeTrunkBackIn.sh Executable file
View File

@@ -0,0 +1,36 @@
svn merge -r 10855:10943 https://svn.cs.uu.nl:12443/repos/trace/nix/trunk
#already done:
# 8628
# 8632
# 8634
# 8636
# 8655
# 8691
# 8698
# 8711
# 8864
# 9063
# 9105
# 9207
# 9217
# 9332
# 9429
# 9433
# 9435
# 9437
# 9439
# 9445
# 9476
# 9506
# 9536
# 9549
# 9561
# 9584
# 9751
# 10133
# 10154
# 10531
# 10692
# 10855
# 10943

35
misc/vim/syntax/nix.vim Normal file
View File

@@ -0,0 +1,35 @@
" Vim syntax file
" Language: nix
" Maintainer: Marc Weber <marco-oweber@gmx.de>
" Modify and commit if you feel that way
" Last Change: 2007 Dec
" Quit when a (custom) syntax file was already loaded
if exists("b:current_syntax")
finish
endif
syn keyword nixKeyword let throw inherit import true false null with
syn keyword nixConditional if else then
syn keyword nixBrace ( ) { } =
syn keyword nixBuiltin __currentSystem __currentTime __isFunction __getEnv __trace __toPath __pathExists
\ __readFile __toXML __toFile __filterSource __attrNames __getAttr __hasAttr __isAttrs __listToAttrs __isList
\ __head __tail __add __sub __lessThan __substring __stringLength
syn match nixAttr "\w\+\ze\s*="
syn match nixFuncArg "\zs\w\+\ze\s*:"
syn region nixStringParam start=+\${+ end=+}+
syn region nixMultiLineComment start=+/\*+ skip=+\\"+ end=+\*/+
syn match nixEndOfLineComment "#.*$"
syn region nixString start=+"+ skip=+\\"+ end=+"+ contains=nixStringParam
hi def link nixKeyword Keyword
hi def link nixConditional Conditional
hi def link nixBrace Special
hi def link nixString String
hi def link nixBuiltin Special
hi def link nixStringParam Macro
hi def link nixMultiLineComment Comment
hi def link nixEndOfLineComment Comment
hi def link nixAttr Identifier
hi def link nixFuncArg Identifier

View File

@@ -78,35 +78,99 @@
#build-max-jobs = 1
### Option `build-allow-root'
### Option `build-max-silent-time'
#
# This option controls Nix's behaviour when it is invoked under the
# `root' user (or setuid-root). If `true' (default), builds are
# performed under the `root' user. If `false', builds are performed
# under one of the users listed in the `build-users' option (see
# below).
#build-allow-root = true
### Option `build-users'
# This option defines the maximum number of seconds that a builder can
# go without producing any data on standard output or standard error.
# This is useful (for instance in a automated build system) to catch
# builds that are stuck in an infinite loop, or to catch remote builds
# that are hanging due to network problems. It can be overriden using
# the `--max-silent-time' command line switch.
#
# This option is only applicable if `build-allow-root' is `false' and
# Nix is invoked under the `root' user (or setuid-root). It contains
# a list of user names under which Nix can execute builds. Builds
# cannot be performed by root since that would allow users to take
# over the system by supplying specially crafted builders; and they
# cannot be performed by the calling user since that would allow
# him/her to influence the build result.
#
# Thus this list should contain a number of `special' user accounts
# created specifically for Nix, e.g., `nix-builder-1',
# `nix-builder-2', and so on. The more users the better, since at
# most a number of builds equal to the number of build users can be
# started.
# The value 0 means that there is no timeout. This is also the
# default.
#
# Example:
# build-users = nix-builder-1 nix-builder-2 nix-builder-3
#build-users =
# build-max-silent-time = 600 # = 10 minutes
#build-max-silent-time = 0
### Option `build-users-group'
#
# This options specifies the Unix group containing the Nix build user
# accounts. In multi-user Nix installations, builds should not
# be performed by the Nix account since that would allow users to
# arbitrarily modify the Nix store and database by supplying specially
# crafted builders; and they cannot be performed by the calling user
# since that would allow him/her to influence the build result.
#
# Therefore, if this option is non-empty and specifies a valid group,
# builds will be performed under the user accounts that are a member
# of the group specified here (as listed in /etc/group). Those user
# accounts should not be used for any other purpose!
#
# Nix will never run two builds under the same user account at the
# same time. This is to prevent an obvious security hole: a malicious
# user writing a Nix expression that modifies the build result of a
# legitimate Nix expression being built by another user. Therefore it
# is good to have as many Nix build user accounts as you can spare.
# (Remember: uids are cheap.)
#
# The build users should have permission to create files in the Nix
# store, but not delete them. Therefore, /nix/store should be owned
# by the Nix account, its group should be the group specified here,
# and its mode should be 1775.
#
# If the build users group is empty, builds will be performed under
# the uid of the Nix process (that is, the uid of the caller if
# $NIX_REMOTE is empty, the uid under which the Nix daemon runs if
# $NIX_REMOTE is `daemon', or the uid that owns the setuid nix-worker
# program if $NIX_REMOTE is `slave'). Obviously, this should not be
# used in multi-user settings with untrusted users.
#
# The default is empty.
#
# Example:
# build-users-group = nix-builders
#build-users-group =
### Option `build-use-chroot'
#
# If set to `true', builds will be performed in a chroot environment,
# i.e., the build will be isolated from the normal file system
# hierarchy and will only see the Nix store, the temporary build
# directory, and the directories configured with the
# `build-chroot-dirs' option (such as /proc and /dev). This is useful
# to prevent undeclared dependencies on files in directories such as
# /usr/bin.
#
# The use of a chroot requires that Nix is run as root (but you can
# still use the "build users" feature to perform builds under
# different users than root). Currently, chroot builds only work on
# Linux because Nix uses "bind mounts" to make the Nix store and other
# directories available inside the chroot.
#
# The default is `false'.
#
# Example:
# build-use-chroot = true
#build-use-chroot = false
### Option `build-chroot-dirs'
#
# When builds are performed in a chroot environment, Nix will mount
# (using `mount --bind' on Linux) some directories from the normal
# file system hierarchy inside the chroot. These are the Nix store,
# the temporary build directory (usually /tmp/nix-<pid>-<number>) and
# the directories listed here. The default is "/dev /proc". Files
# in /dev (such as /dev/null) are needed by many builds, and some
# files in /proc may also be needed occasionally.
#
# Example:
# build-use-chroot = /dev /proc /bin
#build-chroot-dirs = /dev /proc
### Option `system'

View File

@@ -13,7 +13,7 @@ Version: @version@
Release: 1
License: GPL
Group: Software Deployment
URL: http://www.cs.uu.nl/groups/ST/Trace/Nix
URL: http://nix.cs.uu.nl/
Source0: %{name}-@version@.tar.bz2
BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
%define _prefix /nix
@@ -26,7 +26,12 @@ Provides: perl(readmanifest)
%description
Nix is a system for software deployment.
Nix is a purely functional package manager. It allows multiple
versions of a package to be installed side-by-side, ensures that
dependency specifications are complete, supports atomic upgrades and
rollbacks, allows non-root users to install software, and has many
other features. It is the basis of the NixOS Linux distribution, but
it can be used equally well under other Unix systems.
%prep
%setup -q
@@ -73,7 +78,6 @@ fi
%{_prefix}/include
%{_prefix}/var
%{_prefix}/share
%{_prefix}/man
%{_prefix}/store
%config
%{_prefix}/etc

9
restartDaemon.sh Executable file
View File

@@ -0,0 +1,9 @@
#! /bin/sh
initctl stop nix-daemon
killproc.sh nix-worker
sleep 2
#/nixstate2/nix/bin/nix-worker --daemon > /dev/null 2>&1 &
/nixstate2/nix/bin/nix-worker --daemon
#gdb --args /nixstate2/nix/bin/nix-worker --daemon

View File

@@ -1,9 +1,11 @@
bin_SCRIPTS = nix-collect-garbage \
nix-pull nix-push nix-prefetch-url \
nix-install-package nix-channel nix-build \
nix-pack-closure nix-unpack-closure
nix-pack-closure nix-unpack-closure \
nix-copy-closure
noinst_SCRIPTS = nix-profile.sh generate-patches.pl find-runtime-roots.pl
noinst_SCRIPTS = nix-profile.sh generate-patches.pl \
find-runtime-roots.pl build-remote.pl nix-reduce-build
nix-pull nix-push: readmanifest.pm readconfig.pm download-using-manifests.pl
@@ -15,6 +17,8 @@ install-exec-local: readmanifest.pm download-using-manifests.pl find-runtime-roo
$(INSTALL_DATA) readconfig.pm $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) download-using-manifests.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) find-runtime-roots.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) generate-patches.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL_PROGRAM) build-remote.pl $(DESTDIR)$(libexecdir)/nix
$(INSTALL) -d $(DESTDIR)$(sysconfdir)/nix
include ../substitute.mk
@@ -29,4 +33,7 @@ EXTRA_DIST = nix-collect-garbage.in \
download-using-manifests.pl.in \
generate-patches.pl.in \
nix-pack-closure.in nix-unpack-closure.in \
find-runtime-roots.pl.in
nix-copy-closure.in \
find-runtime-roots.pl.in \
build-remote.pl.in \
nix-reduce-build.in

208
scripts/build-remote.pl.in Executable file
View File

@@ -0,0 +1,208 @@
#! @perl@ -w
use strict;
use Fcntl ':flock';
use English '-no_match_vars';
# General operation:
#
# Try to find a free machine of type $neededSystem. We do this as
# follows:
# - We acquire an exclusive lock on $currentLoad/main-lock.
# - For each machine $machine of type $neededSystem and for each $slot
# less than the maximum load for that machine, we try to get an
# exclusive lock on $currentLoad/$machine-$slot (without blocking).
# If we get such a lock, we send "accept" to the caller. Otherwise,
# we send "postpone" and exit.
# - We release the exclusive lock on $currentLoad/main-lock.
# - We perform the build on $neededSystem.
# - We release the exclusive lock on $currentLoad/$machine-$slot.
#
# The nice thing about this scheme is that if we die prematurely, the
# locks are released automatically.
my $loadIncreased = 0;
my $amWilling = shift @ARGV;
my $localSystem = shift @ARGV;
my $neededSystem = shift @ARGV;
my $drvPath = shift @ARGV;
sub sendReply {
my $reply = shift;
open OUT, ">&3" or die;
print OUT "$reply\n";
close OUT;
}
sub decline {
sendReply "decline";
exit 0;
}
my $currentLoad = $ENV{"NIX_CURRENT_LOAD"};
decline unless defined $currentLoad;
mkdir $currentLoad, 0777 or die unless -d $currentLoad;
my $conf = $ENV{"NIX_REMOTE_SYSTEMS"};
decline if !defined $conf || ! -e $conf;
# Decline if the local system can do the build.
decline if $amWilling && ($localSystem eq $neededSystem);
# Otherwise find a willing remote machine.
my %machines;
my %systemTypes;
my %sshKeys;
my %maxJobs;
my %curJobs;
# Read the list of machines.
open CONF, "< $conf" or die;
while (<CONF>) {
chomp;
s/\#.*$//g;
next if /^\s*$/;
/^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\d+)\s*$/ or die;
$machines{$1} = "";
$systemTypes{$1} = $2;
$sshKeys{$1} = $3;
$maxJobs{$1} = $4;
}
close CONF;
# Acquire the exclusive lock on $currentLoad/main-lock.
my $mainLock = "$currentLoad/main-lock";
open MAINLOCK, ">>$mainLock" or die;
flock(MAINLOCK, LOCK_EX) or die;
# Find a suitable system.
my $rightType = 0;
my $machine;
LOOP: foreach my $cur (keys %machines) {
if ($neededSystem eq $systemTypes{$cur}) {
$rightType = 1;
# We have a machine of the right type. Try to get a lock on
# one of the machine's lock files.
my $slot = 0;
while ($slot < $maxJobs{$cur}) {
my $slotLock = "$currentLoad/$cur-$slot";
open SLOTLOCK, ">>$slotLock" or die;
if (flock(SLOTLOCK, LOCK_EX | LOCK_NB)) {
$machine = $cur;
last LOOP;
}
close SLOTLOCK;
$slot++;
}
}
}
close MAINLOCK;
# Didn't find one?
if (!defined $machine) {
if ($rightType) {
sendReply "postpone";
exit 0;
} else {
decline;
}
}
# Yes we did, accept.
sendReply "accept";
open IN, "<&4" or die;
my $x = <IN>;
chomp $x;
#print "got $x\n";
close IN;
if ($x ne "okay") {
exit 0;
}
# Do the actual job.
print "BUILDING REMOTE: $drvPath on $machine\n";
# Make sure that we don't get any SSH passphrase or host key popups -
# if there is any problem it should fail, not do something
# interactive.
$ENV{"DISPLAY"} = "";
$ENV{"SSH_PASSWORD_FILE="} = "";
$ENV{"SSH_ASKPASS="} = "";
my $sshOpts = "-i $sshKeys{$machine} -x";
# Hack to support Cygwin: if we login without a password, we don't
# have exactly the same right as when we do. This causes the
# Microsoft C compiler to fail with certain flags:
#
# http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99676
#
# So as a workaround, we pass a verbatim password. ssh tries to makes
# this very hard; the trick is to make it call SSH_ASKPASS to get the
# password. (It only calls this command when there is no controlling
# terminal, but Nix ensures that is is the case. When doing this
# manually, use setsid(1).)
if ($sshKeys{$machine} =~ /^password:/) {
my $passwordFile = $sshKeys{$machine};
$passwordFile =~ s/^password://;
$sshOpts = "ssh -x";
$ENV{"SSH_PASSWORD_FILE"} = $passwordFile;
$ENV{"SSH_ASKPASS"} = "/tmp/writepass";
open WRITEPASS, ">/tmp/writepass" or die;
print WRITEPASS "#! /bin/sh\ncat \"\$SSH_PASSWORD_FILE\"";
close WRITEPASS;
chmod 0755, "/tmp/writepass" or die;
}
my $inputs = `cat inputs`; die if ($? != 0);
$inputs =~ s/\n/ /g;
my $outputs = `cat outputs`; die if ($? != 0);
$outputs =~ s/\n/ /g;
print "COPYING INPUTS...\n";
my $maybeSign = "";
$maybeSign = "--sign" if -e "/nix/etc/nix/signing-key.sec";
system("NIX_SSHOPTS=\"$sshOpts\" nix-copy-closure $machine $maybeSign $drvPath $inputs") == 0
or die "cannot copy inputs to $machine: $?";
print "BUILDING...\n";
system("ssh $sshOpts $machine 'nix-store -rvvK $drvPath'") == 0
or die "remote build on $machine failed: $?";
print "REMOTE BUILD DONE: $drvPath on $machine\n";
foreach my $output (split '\n', $outputs) {
my $maybeSignRemote = "";
$maybeSignRemote = "--sign" if $UID != 0;
system("ssh $sshOpts $machine 'nix-store --export $maybeSignRemote $output' > dump") == 0
or die "cannot copy $output from $machine: $?";
# This doesn't work yet, since the caller has a lock on the output
# path. We should move towards lock-free invocation of build
# hooks and substitutes.
#system("nix-store --import < dump") == 0
# or die "cannot import $output: $?";
# Hack: skip the first 8 bytes (the nix-store --export next
# archive marker). The archive follows.
system("(dd bs=1 count=8 of=/dev/null && cat) < dump | nix-store --restore $output") == 0
or die "cannot restore $output: $?";
}

View File

@@ -10,8 +10,6 @@ my $logFile = "@localstatedir@/log/nix/downloads";
open LOGFILE, ">>$logFile" or die "cannot open log file $logFile";
delete $ENV{"NIX_ROOT"};
# Create a temporary directory.
my $tmpDir = tempdir("nix-download.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
@@ -21,12 +19,79 @@ chdir $tmpDir or die "cannot change to `$tmpDir': $!";
my $tmpNar = "$tmpDir/nar";
my $tmpNar2 = "$tmpDir/nar2";
END { unlink $tmpNar; unlink $tmpNar2; rmdir $tmpDir; }
# Load all manifests.
my %narFiles;
my %localPaths;
my %patches;
for my $manifest (glob "$manifestDir/*.nixmanifest") {
# print STDERR "reading $manifest\n";
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
exit 1;
}
}
# Check the arguments.
die unless scalar @ARGV == 1;
my $targetPath = $ARGV[0];
# Parse the arguments.
if ($ARGV[0] eq "--query-paths") {
foreach my $storePath (keys %narFiles) { print "$storePath\n"; }
foreach my $storePath (keys %localPaths) { print "$storePath\n"; }
exit 0;
}
elsif ($ARGV[0] eq "--query-info") {
shift @ARGV;
foreach my $storePath (@ARGV) {
my $info;
if (defined $narFiles{$storePath}) {
$info = @{$narFiles{$storePath}}[0];
}
elsif (defined $localPaths{$storePath}) {
$info = @{$localPaths{$storePath}}[0];
}
else {
next; # not an error
}
print "$storePath\n";
print "$info->{deriver}\n";
my @references = split " ", $info->{references};
my $count = scalar @references;
print "$count\n";
foreach my $reference (@references) {
print "$reference\n";
}
my $isStateStorePath = `@bindir@/nix-state --is-state-store-path-download-using-manifests $storePath`;
if($isStateStorePath ne "true" && $isStateStorePath ne "false"){
die "The call for isStateStorePath must return true or false.....";
}
if($isStateStorePath eq "true"){
my @stateReferences = split " ", $info->{stateReferences};
my $scount = scalar @stateReferences;
print "$scount\n";
foreach my $stateReference (@stateReferences) {
print "$stateReference\n";
}
print "$info->{revision}\n";
}
}
exit 0;
}
elsif ($ARGV[0] ne "--substitute") {
die "syntax: $0 [--query-paths | --query-info PATHS... | --substitute PATH]\n";
}
die unless scalar @ARGV == 2;
my $targetPath = $ARGV[1];
my $date = strftime ("%F %H:%M:%S UTC", gmtime (time));
print LOGFILE "$$ get $targetPath $date\n";
@@ -34,16 +99,15 @@ print LOGFILE "$$ get $targetPath $date\n";
print "\n*** Trying to download/patch `$targetPath'\n";
# Load all manifests.
my %narFiles;
my %patches;
my %successors;
for my $manifest (glob "$manifestDir/*.nixmanifest") {
# print STDERR "reading $manifest\n";
if (readManifest($manifest, \%narFiles, \%patches, \%successors) < 3) {
print STDERR "you have an old-style manifest `$manifest'; please delete it\n";
exit 1;
# If we can copy from a local path, do that.
my $localPathList = $localPaths{$targetPath};
foreach my $localPath (@{$localPathList}) {
my $sourcePath = $localPath->{copyFrom};
if (-e $sourcePath) {
print "\n*** Step 1/1: copying from $sourcePath\n";
system("@bindir@/nix-store --dump $sourcePath | @bindir@/nix-store --restore $targetPath") == 0
or die "cannot copy `$sourcePath' to `$targetPath'";
exit 0;
}
}

View File

@@ -56,3 +56,20 @@ sub lsof {
readProc;
lsof;
sub readFile {
my $path = shift;
if (-e $path) {
if (open FILE, "$path") {
while (<FILE>) {
print;
}
close FILE;
}
}
}
# This is rather NixOS-specific, so it probably shouldn't be here.
readFile "/proc/sys/kernel/modprobe";
readFile "/proc/sys/kernel/fbsplash";

View File

@@ -4,6 +4,18 @@ use strict;
use File::Temp qw(tempdir);
use readmanifest;
# Some patch generations options.
# Max size of NAR archives to generate patches for.
my $maxNarSize = $ENV{"NIX_MAX_NAR_SIZE"};
$maxNarSize = 100 * 1024 * 1024 if !defined $maxNarSize;
# If patch is bigger than this fraction of full archive, reject.
my $maxPatchFraction = $ENV{"NIX_PATCH_FRACTION"};
$maxPatchFraction = 0.60 if !defined $maxPatchFraction;
die unless scalar @ARGV == 5;
my $hashAlgo = "sha256";
@@ -22,23 +34,22 @@ print "TEMP = $tmpDir\n";
#END { rmdir $tmpDir; }
my %srcNarFiles;
my %srcLocalPaths;
my %srcPatches;
my %srcSuccessors;
my %dstNarFiles;
my %dstLocalPaths;
my %dstPatches;
my %dstSuccessors;
readManifest "$srcDir/MANIFEST",
\%srcNarFiles, \%srcPatches, \%srcSuccessors;
\%srcNarFiles, \%srcLocalPaths, \%srcPatches;
readManifest "$dstDir/MANIFEST",
\%dstNarFiles, \%dstPatches, \%dstSuccessors;
\%dstNarFiles, \%dstLocalPaths, \%dstPatches;
sub findOutputPaths {
my $narFiles = shift;
my $successors = shift;
my %outPaths;
@@ -63,10 +74,10 @@ sub findOutputPaths {
}
print "finding src output paths...\n";
my %srcOutPaths = findOutputPaths \%srcNarFiles, \%srcSuccessors;
my %srcOutPaths = findOutputPaths \%srcNarFiles;
print "finding dst output paths...\n";
my %dstOutPaths = findOutputPaths \%dstNarFiles, \%dstSuccessors;
my %dstOutPaths = findOutputPaths \%dstNarFiles;
sub getNameVersion {
@@ -277,8 +288,6 @@ foreach my $p (keys %dstOutPaths) {
my $srcNarBz2 = getNarBz2 \%srcNarFiles, $closest;
my $dstNarBz2 = getNarBz2 \%dstNarFiles, $p;
my $maxNarSize = 150 * 1024 * 1024;
system("@bunzip2@ < $srcNarBz2 > $tmpDir/A") == 0
or die "cannot unpack $srcNarBz2";
@@ -310,16 +319,21 @@ foreach my $p (keys %dstOutPaths) {
my $narDiffSize = (stat "$tmpDir/DIFF")[7];
my $dstNarBz2Size = (stat $dstNarBz2)[7];
print " size $narDiffSize; full size $dstNarBz2Size\n";
if ($narDiffSize >= $dstNarBz2Size) {
print " rejecting; patch bigger than full archive\n";
next;
}
if ($narDiffSize / $dstNarBz2Size >= $maxPatchFraction) {
print " rejecting; patch too large relative to full archive\n";
next;
}
my $finalName =
"$narDiffHash.nar-bsdiff";
print " size $narDiffSize; full size $dstNarBz2Size\n";
if (-e "$patchesDir/$finalName") {
print " not copying, already exists\n";
}
@@ -348,11 +362,22 @@ foreach my $p (keys %dstOutPaths) {
# patches that produce either paths in the destination or paths that
# can be used as the base for other useful patches).
print "propagating patches...\n";
my $changed;
do {
# !!! we repeat this to reach the transitive closure; inefficient
$changed = 0;
print "loop\n";
my %dstBasePaths;
foreach my $q (keys %dstPatches) {
foreach my $patch (@{$dstPatches{$q}}) {
$dstBasePaths{$patch->{basePath}} = 1;
}
}
foreach my $p (keys %srcPatches) {
my $patchList = $srcPatches{$p};
@@ -360,22 +385,18 @@ do {
# Is path $p included in the destination? If so, include
# patches that produce it.
$include = 1 if (defined $dstNarFiles{$p});
$include = 1 if defined $dstNarFiles{$p};
# Is path $p a path that serves as a base for paths in the
# destination? If so, include patches that produce it.
foreach my $q (keys %dstPatches) {
foreach my $patch (@{$dstPatches{$q}}) {
# !!! check baseHash
$include = 1 if ($p eq $patch->{basePath});
}
}
# !!! check baseHash
$include = 1 if defined $dstBasePaths{$p};
if ($include) {
foreach my $patch (@{$patchList}) {
$changed = 1 if addPatch \%dstPatches, $p, $patch;
}
}
}
}
@@ -384,4 +405,4 @@ do {
# Rewrite the manifest of the destination (with the new patches).
writeManifest "$dstDir/MANIFEST",
\%dstNarFiles, \%dstPatches, \%dstSuccessors;
\%dstNarFiles, \%dstPatches;

View File

@@ -7,12 +7,12 @@ use readcache;
# Read the manifests.
my %narFiles;
my %localPaths;
my %patches;
my %successors;
foreach my $manifest (@ARGV) {
print STDERR "loading $manifest\n";
if (readManifest($manifest, \%narFiles, \%patches, \%successors, 1) < 3) {
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches, 1) < 3) {
# die "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
}
}

View File

@@ -15,7 +15,7 @@ sub readDir {
}
readDir "/data/webserver/dist/nix-cache";
readDir "/data/webserver/dist/test";
readDir "/data/webserver/dist/test-cache";
readDir "/data/webserver/dist/patches";
print STDERR scalar (keys %archives), "\n";

View File

@@ -6,12 +6,12 @@ use readcache;
my %allNarFiles;
my %allLocalPaths;
my %allPatches;
my %allSuccessors;
foreach my $manifest (glob "/data/webserver/dist/*/*/MANIFEST") {
print STDERR "loading $manifest\n";
readManifest($manifest, \%allNarFiles, \%allPatches, \%allSuccessors, 1);
readManifest($manifest, \%allNarFiles, \%allLocalPaths, \%allPatches, 1);
}
@@ -22,9 +22,8 @@ foreach my $manifest (@ARGV) {
my %narFiles;
my %patches;
my %successors;
if (readManifest($manifest, \%narFiles, \%patches, \%successors, 1) < 3) {
if (readManifest($manifest, \%narFiles, \%patches, 1) < 3) {
print STDERR "manifest `$manifest' is too old (i.e., for Nix <= 0.7)\n";
next;
}

View File

@@ -56,7 +56,7 @@ EOF
}
elsif ($arg eq "--no-out-link" or $arg eq "--no-link") {
$addOutLink = 1;
$addOutLink = 0;
}
elsif ($arg eq "--drv-link") {
@@ -77,12 +77,18 @@ EOF
push @instArgs, ("--attr", $ARGV[$n]);
}
elsif ($arg eq "--arg") {
die "$0: `--arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
push @instArgs, ("--arg", $ARGV[$n + 1], $ARGV[$n + 2]);
elsif ($arg eq "--arg" || $arg eq "--argstr") {
die "$0: `$arg' requires two arguments\n" unless $n + 2 < scalar @ARGV;
push @instArgs, ($arg, $ARGV[$n + 1], $ARGV[$n + 2]);
$n += 2;
}
elsif ($arg eq "--max-jobs" or $arg eq "-j" or $arg eq "--max-silent-time") {
$n++;
die "$0: `$arg' requires an argument\n" unless $n < scalar @ARGV;
push @buildArgs, ($arg, $ARGV[$n]);
}
elsif (substr($arg, 0, 1) eq "-") {
push @buildArgs, $arg;
}
@@ -116,17 +122,19 @@ foreach my $expr (@exprs) {
close DRVPATHS or exit 1;
foreach my $drvPath (@drvPaths) {
my $target = readlink $drvPath;
my $target = readlink $drvPath or die "cannot read symlink `$drvPath'";
print STDERR "store derivation is $target\n";
}
# Build.
my $outPaths = `@bindir@/nix-store --add-root "$outLink" --indirect -rv @buildArgs @drvPaths`;
my @outPaths = split ' ', $outPaths;
my @outPaths;
$pid = open(OUTPATHS, "-|") || exec "@bindir@/nix-store", "--add-root", $outLink, "--indirect", "-rv",
@buildArgs, @drvPaths;
while (<OUTPATHS>) {chomp; push @outPaths, $_;}
close OUTPATHS or exit 1;
foreach my $outPath (@outPaths) {
my $target = readlink $outPath;
my $target = readlink $outPath or die "cannot read symlink `$outPath'";
print "$target\n";
}
}

View File

@@ -2,16 +2,24 @@
use strict;
my $rootsDir = "@localstatedir@/nix/gcroots/channels";
my $rootsDir = "@localstatedir@/nix/gcroots";
my $stateDir = $ENV{"NIX_STATE_DIR"};
$stateDir = "@localstatedir@/nix" unless defined $stateDir;
# Turn on caching in nix-prefetch-url.
my $channelCache = "$stateDir/channel-cache";
mkdir $channelCache, 0755 unless -e $channelCache;
$ENV{'NIX_DOWNLOAD_CACHE'} = $channelCache if -W $channelCache;
# Figure out the name of the `.nix-channels' file to use.
my $home = $ENV{"HOME"};
die '$HOME not set' unless defined $home;
my $channelsList = "$home/.nix-channels";
my $nixDefExpr = "$home/.nix-defexpr";
my @channels;
@@ -70,48 +78,56 @@ sub removeChannel {
sub update {
readChannels;
# Get rid of all the old substitutes.
system("@bindir@/nix-store", "--clear-substitutes") == 0
or die "cannot clear substitutes";
# Do we have write permission to the manifests directory? If not,
# then just skip pulling the manifest and just download the Nix
# expressions. If the user is a non-privileged user in a
# multi-user Nix installation, he at least gets installation from
# source.
if (-W "$stateDir/manifests") {
# Remove all the old manifests.
for my $manifest (glob "$stateDir/manifests/*.nixmanifest") {
unlink $manifest or die "cannot remove `$manifest': $!";
}
# Remove all the old manifests.
for my $manifest (glob "$stateDir/manifests/*.nixmanifest") {
unlink $manifest or die "cannot remove `$manifest': $!";
}
# Pull cache manifests.
foreach my $url (@channels) {
#print "pulling cache manifest from `$url'\n";
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull cache manifest from `$url'";
}
# Pull cache manifests.
foreach my $url (@channels) {
print "pulling cache manifest from `$url'\n";
system("@bindir@/nix-pull", "--skip-wrong-store", "$url/MANIFEST") == 0
or die "cannot pull cache manifest from `$url'";
}
# Create a Nix expression that fetches and unpacks the channel Nix
# expressions.
my $nixExpr = "[";
my $inputs = "[";
foreach my $url (@channels) {
$url =~ /\/([^\/]+)\/?$/;
my $channelName = $1;
$channelName = "unnamed" unless defined $channelName;
my $fullURL = "$url/nixexprs.tar.bz2";
print "downloading Nix expressions from `$fullURL'...\n";
$ENV{"PRINT_PATH"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL' 2> /dev/null`;
$ENV{"QUIET"} = 1;
my ($hash, $path) = `@bindir@/nix-prefetch-url '$fullURL'`;
die "cannot fetch `$fullURL'" if $? != 0;
chomp $path;
$nixExpr .= $path . " ";
$inputs .= '"' . $channelName . '"' . " " . $path . " ";
}
$nixExpr .= "]";
$nixExpr =
"(import @datadir@/nix/corepkgs/channels/unpack.nix) " .
"{inputs = $nixExpr; system = \"@system@\";}";
$inputs .= "]";
# Figure out a name for the GC root.
my $userName = getpwuid($<);
die "who ARE you? go away" unless defined $userName;
my $rootFile = "$rootsDir/$userName";
my $rootFile = "$rootsDir/per-user/$userName/channels";
# Instantiate the Nix expression.
my $storeExpr = `echo '$nixExpr' | @bindir@/nix-instantiate --add-root '$rootFile'.tmp -`
print "unpacking channel Nix expressions...\n";
my $storeExpr = `@bindir@/nix-instantiate --add-root '$rootFile'.tmp @datadir@/nix/corepkgs/channels/unpack.nix --argstr system @system@ --arg inputs '$inputs'`
or die "cannot instantiate Nix expression";
chomp $storeExpr;
@@ -122,9 +138,12 @@ sub update {
unlink "$rootFile.tmp";
# Make it the default Nix expression for `nix-env'.
system("@bindir@/nix-env", "--import", "$outPath") == 0
or die "cannot pull set default Nix expression to `$outPath'";
# Make the channels appear in nix-env.
unlink $nixDefExpr if -l $nixDefExpr; # old-skool ~/.nix-defexpr
mkdir $nixDefExpr or die "cannot create directory `$nixDefExpr'" if !-e $nixDefExpr;
my $channelLink = "$nixDefExpr/channels";
unlink $channelLink; # !!! not atomic
symlink($outPath, $channelLink) or die "cannot symlink `$channelLink' to `$outPath'";
}

View File

@@ -21,22 +21,31 @@ for my $arg (@ARGV) {
# If `-d' was specified, remove all old generations of all profiles.
# Of course, this makes rollbacks to before this point in time
# impossible.
if ($removeOld) {
opendir DIR, $profilesDir or die;
sub removeOldGenerations;
sub removeOldGenerations {
my $dir = shift;
foreach my $name (sort (readdir DIR)) {
$name = $profilesDir . "/" . $name;
my $dh;
opendir $dh, $dir or die;
foreach my $name (sort (readdir $dh)) {
next if $name eq "." || $name eq "..";
$name = $dir . "/" . $name;
if (-l $name && (readlink($name) =~ /link/)) {
print STDERR "removing old generations of profile $name\n";
system("@bindir@/nix-env", "-p", $name, "--delete-generations", "old");
}
elsif (! -l $name && -d $name) {
removeOldGenerations $name;
}
}
closedir DIR or die;
closedir $dh or die;
}
removeOldGenerations $profilesDir if $removeOld;
# Run the actual garbage collector.
exec "@bindir@/nix-store", "--gc", @args;

148
scripts/nix-copy-closure.in Normal file
View File

@@ -0,0 +1,148 @@
#! @perl@ -w
my $binDir = $ENV{"NIX_BIN_DIR"};
$binDir = "@bindir@" unless defined $binDir;
if (scalar @ARGV < 1) {
print STDERR <<EOF
Usage: nix-copy-closure [--from | --to] HOSTNAME [--sign] [--gzip] PATHS...
EOF
;
exit 1;
}
# Get the target host.
my $sshHost;
my @sshOpts = split ' ', ($ENV{"NIX_SSHOPTS"} or "");
my $sign = 0;
my $compressor = "cat";
my $decompressor = "cat";
my $toMode = 1;
# !!! Copied from nix-pack-closure, should put this in a module.
my @storePaths = ();
while (@ARGV) {
my $arg = shift @ARGV;
if ($arg eq "--sign") {
$sign = 1;
}
elsif ($arg eq "--gzip") {
$compressor = "gzip";
$decompressor = "gunzip";
}
elsif ($arg eq "--from") {
$toMode = 0;
}
elsif ($arg eq "--to") {
$toMode = 1;
}
elsif (!defined $sshHost) {
$sshHost = $arg;
}
else {
push @storePaths, $arg;
}
}
if ($toMode) { # Copy TO the remote machine.
my @allStorePaths;
my %storePathsSeen;
foreach my $storePath (@storePaths) {
# $arg might be a symlink to the store, so resolve it.
my $storePath2 = (`$binDir/nix-store --query --resolve '$storePath'`
or die "cannot resolve `$storePath'");
chomp $storePath2;
# Get the closure of this path.
my $pid = open(READ,
"$binDir/nix-store --query --requisites '$storePath2'|") or die;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
if (!defined $storePathsSeen{$_}) {
push @allStorePaths, $_;
$storePathsSeen{$_} = 1;
}
}
close READ or die "nix-store failed: $?";
}
# Ask the remote host which paths are invalid.
open(READ, "ssh @sshOpts $sshHost nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
print STDERR "target machine needs $_\n";
push @missing, $_;
}
close READ or die;
# Export the store paths and import them on the remote machine.
if (scalar @missing > 0) {
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("nix-store --export $extraOpts @missing | $compressor | ssh @sshOpts $sshHost '$decompressor | nix-store --import'") == 0
or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}
else { # Copy FROM the remote machine.
# Query the closure of the given store paths on the remote
# machine. Paths are assumed to be store paths; there is no
# resolution (following of symlinks).
my $pid = open(READ,
"ssh @sshOpts $sshHost nix-store --query --requisites @storePaths|") or die;
my @allStorePaths;
my %storePathsSeen;
while (<READ>) {
chomp;
die "bad: $_" unless /^\//;
if (!defined $storePathsSeen{$_}) {
push @allStorePaths, $_;
$storePathsSeen{$_} = 1;
}
}
close READ or die "nix-store on remote machine `$sshHost' failed: $?";
# What paths are already valid locally?
open(READ, "@bindir@/nix-store --check-validity --print-invalid @allStorePaths|");
my @missing = ();
while (<READ>) {
chomp;
print STDERR "local machine needs $_\n";
push @missing, $_;
}
close READ or die;
# Export the store paths on the remote machine and import them on locally.
if (scalar @missing > 0) {
my $extraOpts = "";
$extraOpts .= "--sign" if $sign == 1;
system("ssh @sshOpts $sshHost 'nix-store --export $extraOpts @missing | $compressor' | $decompressor | @bindir@/nix-store --import") == 0
or die "copying store paths to remote machine `$sshHost' failed: $?";
}
}

View File

@@ -13,7 +13,7 @@ downloading it from URL.
Flags:
--profile / -p LINK: install into the specified profile
--non-interactive: don't run inside a new terminal XXX
--non-interactive: don't run inside a new terminal
EOF
; # '
exit 1;

View File

@@ -17,10 +17,11 @@ $binDir = "@bindir@" unless defined $binDir;
my $tmpDir = tempdir("nix-pack-closure.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
mkdir "$tmpDir/contents", 0777 or die;
mkdir "$tmpDir/references", 0777 or die;
mkdir "$tmpDir/derivers", 0777 or die;
mkdir "$tmpDir/contents", 0755 or die;
mkdir "$tmpDir/references", 0755 or die;
mkdir "$tmpDir/derivers", 0755 or die;
open TOPLEVEL, ">$tmpDir/top-level" or die;
my %storePaths;
@@ -29,6 +30,12 @@ my %storePaths;
while (@ARGV) {
my $storePath = shift @ARGV;
# $storePath might be a symlink to the store, so resolve it.
$storePath = (`$binDir/nix-store --query --resolve '$storePath'`
or die "cannot resolve `$storePath'");
chomp $storePath;
print TOPLEVEL $storePath, "\n";
# Get the closure of this path.
my $pid = open(READ,
"$binDir/nix-store --query --requisites '$storePath'|") or die;
@@ -43,6 +50,9 @@ while (@ARGV) {
}
close TOPLEVEL or die;
foreach my $storePath (sort(keys %storePaths)) {
print STDERR "packing `$storePath'...\n";

View File

@@ -3,15 +3,12 @@
url=$1
expHash=$2
# to prevent doing more than 1 chroot
unset NIX_ROOT
# needed to make it work on NixOS
export PATH=$PATH:@coreutils@
hashType=$NIX_HASH_ALGO
if test -z "$hashType"; then
hashType=md5
hashType=sha256
fi
hashFormat=
@@ -39,29 +36,94 @@ if test -n "$expHash"; then
fi
mkTempDir() {
local i=0
while true; do
if test -z "$TMPDIR"; then TMPDIR=/tmp; fi
tmpPath=$TMPDIR/nix-prefetch-url-$$-$i
if mkdir "$tmpPath"; then break; fi
# !!! to bad we can't check for ENOENT in mkdir, so this check
# is slightly racy (it bombs out if somebody just removed
# $tmpPath...).
if ! test -e "$tmpPath"; then exit 1; fi
i=$((i + 1))
done
trap removeTempDir EXIT SIGINT SIGQUIT
}
removeTempDir() {
if test -n "$tmpPath"; then
rm -rf "$tmpPath" || true
fi
}
doDownload() {
@curl@ $cacheFlags --fail -# --location --max-redirs 20 --disable-epsv \
--cookie-jar $tmpPath/cookies "$url" -o $tmpFile
}
# If we don't know the hash or a file with that hash doesn't exist,
# download the file and add it to the store.
if test -z "$finalPath"; then
tmpPath=/tmp/nix-prefetch-url-$$ # !!! security?
mkTempDir
tmpFile=$tmpPath/$name
mkdir $tmpPath
# Optionally do timestamp-based caching of the download.
# Actually, the only thing that we cache in $NIX_DOWNLOAD_CACHE is
# the hash and the timestamp of the file at $url. The caching of
# the file *contents* is done in Nix store, where it can be
# garbage-collected independently.
if test -n "$NIX_DOWNLOAD_CACHE"; then
echo -n "$url" > $tmpPath/url
urlHash=$(nix-hash --type sha256 --base32 --flat $tmpPath/url)
echo "$url" > "$NIX_DOWNLOAD_CACHE/$urlHash.url"
cachedHashFN="$NIX_DOWNLOAD_CACHE/$urlHash.$hashType"
cachedTimestampFN="$NIX_DOWNLOAD_CACHE/$urlHash.stamp"
cacheFlags="--remote-time"
if test -e "$cachedTimestampFN" -a -e "$cachedHashFN"; then
# Only download the file if it is newer than the cached version.
cacheFlags="$cacheFlags --time-cond $cachedTimestampFN"
fi
fi
# Perform the download.
@curl@ --fail --location --max-redirs 20 "$url" > $tmpFile
doDownload
# Compute the hash.
hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi
if test -n "$NIX_DOWNLOAD_CACHE" -a ! -e $tmpFile; then
# Curl didn't create $tmpFile, so apparently there's no newer
# file on the server.
hash=$(cat $cachedHashFN)
finalPath=$(@bindir@/nix-store --print-fixed-path "$hashType" "$hash" "$name")
if ! @bindir@/nix-store --check-validity "$finalPath" 2> /dev/null; then
echo "cached contents of \`$url' disappeared, redownloading..." >&2
finalPath=
cacheFlags="--remote-time"
doDownload
fi
fi
# Add the downloaded file to the Nix store.
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
if test -z "$finalPath"; then
if test -n "$tmpPath"; then rm -rf $tmpPath || true; fi
# Compute the hash.
hash=$(@bindir@/nix-hash --type "$hashType" $hashFormat --flat $tmpFile)
if ! test -n "$QUIET"; then echo "hash is $hash" >&2; fi
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'"
exit 1
if test -n "$NIX_DOWNLOAD_CACHE"; then
echo $hash > $cachedHashFN
touch -r $tmpFile $cachedTimestampFN
fi
# Add the downloaded file to the Nix store.
finalPath=$(@bindir@/nix-store --add-fixed "$hashType" $tmpFile)
if test -n "$expHash" -a "$expHash" != "$hash"; then
echo "hash mismatch for URL \`$url'" >&2
exit 1
fi
fi
fi

View File

@@ -7,8 +7,6 @@ use readmanifest;
my $tmpDir = tempdir("nix-pull.XXXXXX", CLEANUP => 1, TMPDIR => 1)
or die "cannot create a temporary directory";
my $manifest = "$tmpDir/manifest";
my $binDir = $ENV{"NIX_BIN_DIR"};
$binDir = "@bindir@" unless defined $binDir;
@@ -21,6 +19,11 @@ $stateDir = "@localstatedir@/nix" unless defined $stateDir;
my $storeDir = $ENV{"NIX_STORE_DIR"};
$storeDir = "@storedir@" unless defined $storeDir;
my $storeStateDir = $ENV{"NIX_STORE_STATE_DIR"};
$storeStateDir = "@storestatedir@" unless defined $storeStateDir;
my $ext3cowheader = $ENV{"NIX_EXT3_COW_HEADER"};
$ext3cowheader = "@ext3cowheader@" unless defined $ext3cowheader;
# Prevent access problems in shared-stored installations.
umask 0022;
@@ -28,23 +31,52 @@ umask 0022;
# Process the URLs specified on the command line.
my %narFiles;
my %localPaths;
my %patches;
my %successors;
my $skipWrongStore = 0;
sub downloadFile {
my $url = shift;
$ENV{"PRINT_PATH"} = 1;
$ENV{"QUIET"} = 1;
my ($dummy, $path) = `$binDir/nix-prefetch-url '$url'`;
die "cannot fetch `$url'" if $? != 0;
die "nix-prefetch-url did not return a path" unless defined $path;
chomp $path;
return $path;
}
sub processURL {
my $url = shift;
$url =~ s/\/$//;
print "obtaining list of Nix archives at $url...\n";
system("@curl@ --fail --silent --show-error --location --max-redirs 20 " .
"'$url' > '$manifest'") == 0
or die "curl failed: $?";
my $manifest;
if (readManifest($manifest, \%narFiles, \%patches, \%successors) < 3) {
die "manifest `$url' is too old (i.e., for Nix <= 0.7)\n";
# First see if a bzipped manifest is available.
if (system("@curl@ --fail --silent --head '$url'.bz2 > /dev/null") == 0) {
print "obtaining list of Nix archives at `$url.bz2'...\n";
my $bzipped = downloadFile "$url.bz2";
$manifest = "$tmpDir/MANIFEST";
system("@bunzip2@ < $bzipped > $manifest") == 0
or die "cannot decompress manifest";
$manifest = (`$binDir/nix-store --add $manifest`
or die "cannot copy $manifest to the store");
chomp $manifest;
}
# Otherwise, just get the uncompressed manifest.
else {
print "obtaining list of Nix archives at `$url'...\n";
$manifest = downloadFile $url;
}
if (readManifest($manifest, \%narFiles, \%localPaths, \%patches) < 3) {
die "`$url' is not manifest or it is too old (i.e., for Nix <= 0.7)\n";
}
if ($skipWrongStore) {
@@ -67,8 +99,8 @@ sub processURL {
my $finalPath = "$stateDir/manifests/$baseName-$hash.nixmanifest";
system ("@coreutils@/mv", "-f", "$manifest", "$finalPath") == 0
or die "cannot move `$manifest' to `$finalPath";
system("@coreutils@/ln", "-sfn", "$manifest", "$finalPath") == 0
or die "cannot link `$finalPath to `$manifest'";
}
while (@ARGV) {
@@ -81,30 +113,5 @@ while (@ARGV) {
}
my $size = scalar (keys %narFiles);
my $size = scalar (keys %narFiles) + scalar (keys %localPaths);
print "$size store paths in manifest\n";
# Register all substitutes.
print STDERR "registering substitutes...\n";
my $pid = open(WRITE, "|$binDir/nix-store --register-substitutes")
or die "cannot run nix-store";
foreach my $storePath (keys %narFiles) {
my $narFileList = $narFiles{$storePath};
foreach my $narFile (@{$narFileList}) {
print WRITE "$storePath\n";
print WRITE "$narFile->{deriver}\n";
print WRITE "$libexecDir/nix/download-using-manifests.pl\n";
print WRITE "0\n";
my @references = split " ", $narFile->{references};
my $count = scalar @references;
print WRITE "$count\n";
foreach my $reference (@references) {
print WRITE "$reference\n";
}
}
}
close WRITE or die "nix-store failed: $?";

View File

@@ -116,9 +116,9 @@ print NIX "]";
close NIX;
# Instantiate store expressions from the Nix expression.
# Instantiate store derivations from the Nix expression.
my @storeExprs;
print STDERR "instantiating store expressions...\n";
print STDERR "instantiating store derivations...\n";
my $pid = open(READ, "$binDir/nix-instantiate $nixExpr|")
or die "cannot run nix-instantiate";
while (<READ>) {
@@ -146,7 +146,7 @@ while (scalar @tmp > 0) {
# probably wouldn't make that much sense; pumping lots of data
# around just to compress them won't gain that much.
$ENV{"NIX_BUILD_HOOK"} = "";
my $pid = open(READ, "$binDir/nix-store --realise @tmp2|")
my $pid = open(READ, "$binDir/nix-store --no-build-hook --realise @tmp2|")
or die "cannot run nix-store";
while (<READ>) {
chomp;
@@ -264,8 +264,12 @@ foreach my $narArchive (@narArchives) {
print STDERR "uploading manifest...\n";
if ($localCopy) {
copyFile $manifest, $localManifestFile;
copyFile "$manifest.bz2", "$localManifestFile.bz2";
} else {
system("$curl --show-error --upload-file " .
system("$curl --show-error --upload-file " .
"'$manifest' '$manifestPutURL' > /dev/null") == 0 or
die "curl failed on $manifest: $?";
system("$curl --show-error --upload-file " .
"'$manifest'.bz2 '$manifestPutURL'.bz2 > /dev/null") == 0 or
die "curl failed on $manifest: $?";
}

View File

@@ -0,0 +1,68 @@
#! @shell@
WORKING_DIRECTORY=$(mktemp -d "${TMPDIR:-/tmp}"/nix-reduce-build-XXXXXX);
cd "$WORKING_DIRECTORY";
if test -z "$1" ; then
echo 'nix-reduce-build (paths or Nix expressions) -- (logins at remote computers)' >&2
echo As in: >&2
echo nix-reduce-build /etc/nixos/nixos -- user@somewhere.nowhere.example.org >&2
exit;
fi;
while ! test "$1" = "--" || test "$1" = "" ; do
echo "$1" >> initial; >&2
shift;
done
shift;
echo Will work on $(cat initial | wc -l) targets. >&2
while read ; do
case "$REPLY" in
${NIX_STORE_PATH:-/nix/store}/*)
echo "$REPLY" >> paths; >&2
;;
*)
nix-instantiate "$REPLY" >> paths;
;;
esac;
done < initial;
echo Proceeding $(cat paths | wc -l) paths. >&2
while read; do
case "$REPLY" in
*.drv)
echo "$REPLY" >> derivers; >&2
;;
*)
nix-store --query --deriver "$REPLY" >>derivers;
;;
esac;
done < paths;
echo Found $(cat derivers | wc -l) derivers. >&2
cat derivers | xargs nix-store --query -R > derivers-closure;
echo Proceeding at most $(cat derivers-closure | wc -l) derivers. >&2
cat derivers-closure | egrep '[.]drv$' | xargs nix-store --query --outputs > wanted-paths;
cat derivers-closure | egrep -v '[.]drv$' >> wanted-paths;
echo Prepared $(cat wanted-paths | wc -l) paths to get. >&2
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
echo We need $(cat needed-paths | wc -l) paths. >&2
if test -z "$1" ; then
cat needed-paths;
fi;
for i in "$@"; do
cat needed-paths | while read; do
nix-copy-closure --from "$i" --gzip "$REPLY" </dev/null || true;
done;
mv needed-paths wanted-paths;
cat wanted-paths | xargs nix-store --check-validity --print-invalid > needed-paths;
echo We still need $(cat needed-paths | wc -l) paths. >&2
done;
cd /
rm -r "$WORKING_DIRECTORY"

View File

@@ -77,3 +77,12 @@ closedir(DIR) or die;
# Register the invalid paths as valid.
system("nix-store --register-validity <'$tmpDir/validity'") == 0
or die "nix-store --register-validity failed";
# Show the top-level paths so that something useful can be done with
# them, e.g., passing them to `nix-env -i'.
if (-e "$tmpDir/unpacked/top-level") {
open TOPLEVEL, "<$tmpDir/unpacked/top-level" or die;
while (<TOPLEVEL>) { print "$_"; }
close TOPLEVEL;
}

View File

@@ -1,91 +0,0 @@
#! /usr/bin/perl -w
use strict;
use File::Basename;
my @paths = ("/nix/store");
print "hashing...\n";
my $hashList = "/tmp/nix-optimise-hash-list";
system("find @paths -type f -print0 | xargs -0 md5sum -- > $hashList") == 0
or die "cannot hash store files";
print "sorting by hash...\n";
system("sort $hashList > $hashList.sorted") == 0
or die "cannot sort list";
sub atomicLink {
my $target = shift;
my $new = shift;
my $tmpNew = "${new}_optimise.$$";
# Make the directory writable temporarily.
my $dir = dirname $new;
my @st = stat $dir or die;
chmod ($st[2] | 0200, $dir) or die "cannot make `$dir' writable: $!";
link $target, $tmpNew or die "cannot create hard link `$tmpNew': $!";
rename $tmpNew, $new or die "cannot rename `$tmpNew' to `$new': $!";
chmod ($st[2], $dir) or die "cannot restore permission on `$dir': $!";
utime ($st[8], $st[9], $dir) or die "cannot restore timestamp on `$dir': $!";
}
print "hard-linking...\n";
open LIST, "<$hashList.sorted" or die;
my $prevFile;
my $prevHash;
my $prevInode;
my $prevExec;
my $totalSpace = 0;
my $savedSpace = 0;
while (<LIST>) {
/^([0-9a-f]*)\s+(.*)$/ or die;
my $curFile = $2;
my $curHash = $1;
my @st = stat $curFile or die;
next if ($st[2] & 0222) != 0; # skip writable files
my $fileSize = $st[7];
$totalSpace += $fileSize;
my $isExec = ($st[2] & 0111) == 0111;
if (defined $prevHash && $curHash eq $prevHash
&& $prevExec == $isExec)
{
if ($st[1] != $prevInode) {
print "$curFile = $prevFile\n";
atomicLink $prevFile, $curFile;
$savedSpace += $fileSize;
}
} else {
$prevFile = $curFile;
$prevHash = $curHash;
$prevInode = $st[1];
$prevExec = ($st[2] & 0111) == 0111;
}
}
print "total space = $totalSpace\n";
print "saved space = $savedSpace\n";
my $savings = ($savedSpace / $totalSpace) * 100.0;
print "savings = $savings %\n";
close LIST;

View File

@@ -34,8 +34,8 @@ sub addPatch {
sub readManifest {
my $manifest = shift;
my $narFiles = shift;
my $localPaths = shift;
my $patches = shift;
my $successors = shift;
my $allowConflicts = shift;
$allowConflicts = 0 unless defined $allowConflicts;
@@ -51,7 +51,6 @@ sub readManifest {
my $url;
my $hash;
my $size;
my @preds;
my $basePath;
my $baseHash;
my $patchType;
@@ -59,6 +58,7 @@ sub readManifest {
my $references;
my $deriver;
my $hashAlgo;
my $copyFrom;
while (<MANIFEST>) {
chomp;
@@ -75,7 +75,6 @@ sub readManifest {
undef $url;
undef $hash;
undef $size;
@preds = ();
undef $narHash;
undef $basePath;
undef $baseHash;
@@ -117,10 +116,6 @@ sub readManifest {
};
}
foreach my $p (@preds) {
$$successors{$p} = $storePath;
}
}
elsif ($type eq "patch") {
@@ -132,13 +127,29 @@ sub readManifest {
}, $allowConflicts;
}
elsif ($type eq "localPath") {
$$localPaths{$storePath} = []
unless defined $$localPaths{$storePath};
my $localPathsList = $$localPaths{$storePath};
# !!! remove duplicates
push @{$localPathsList},
{ copyFrom => $copyFrom, references => $references
, deriver => ""
};
}
}
elsif (/^\s*StorePath:\s*(\/\S+)\s*$/) { $storePath = $1; }
elsif (/^\s*CopyFrom:\s*(\/\S+)\s*$/) { $copyFrom = $1; }
elsif (/^\s*Hash:\s*(\S+)\s*$/) { $hash = $1; }
elsif (/^\s*URL:\s*(\S+)\s*$/) { $url = $1; }
elsif (/^\s*Size:\s*(\d+)\s*$/) { $size = $1; }
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { push @preds, $1; }
elsif (/^\s*SuccOf:\s*(\/\S+)\s*$/) { } # obsolete
elsif (/^\s*BasePath:\s*(\/\S+)\s*$/) { $basePath = $1; }
elsif (/^\s*BaseHash:\s*(\S+)\s*$/) { $baseHash = $1; }
elsif (/^\s*Type:\s*(\S+)\s*$/) { $patchType = $1; }
@@ -165,6 +176,7 @@ sub writeManifest
my $manifest = shift;
my $narFiles = shift;
my $patches = shift;
my $copySources = shift;
open MANIFEST, ">$manifest.tmp"; # !!! check exclusive
@@ -210,6 +222,14 @@ sub writeManifest
rename("$manifest.tmp", $manifest)
or die "cannot rename $manifest.tmp: $!";
# Create a bzipped manifest.
system("@bzip2@ < $manifest > $manifest.bz2.tmp") == 0
or die "cannot compress manifest";
rename("$manifest.bz2.tmp", "$manifest.bz2")
or die "cannot rename $manifest.bz2.tmp: $!";
}

View File

@@ -6,14 +6,12 @@ use readmanifest;
for my $p (@ARGV) {
my %narFiles;
my %localPaths;
my %patches;
my %successors;
readManifest $p,
\%narFiles, \%patches, \%successors;
readManifest $p, \%narFiles, \%localPaths, \%patches;
%patches = ();
writeManifest $p,
\%narFiles, \%patches, \%successors;
writeManifest $p, \%narFiles, \%patches;
}

View File

@@ -8,10 +8,10 @@ die unless scalar @ARGV == 2;
my $cache = $ARGV[0];
my $manifest = $ARGV[1];
my %narFiles;
my %localPaths;
my %patches;
my %successors;
readManifest $manifest, \%narFiles, \%patches, \%successors;
readManifest $manifest, \%narFiles, \%localPaths, \%patches;
foreach my $storePath (keys %narFiles) {
my $narFileList = $narFiles{$storePath};
@@ -50,4 +50,4 @@ if (! -e "$manifest.backup") {
system "mv --reply=no '$manifest' '$manifest.backup'";
}
writeManifest $manifest, \%narFiles, \%patches, \%successors;
writeManifest $manifest, \%narFiles, \%patches;

View File

@@ -1,15 +1,5 @@
SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env nix-log2xml bsdiff-4.3
SUBDIRS = bin2c boost libutil libext3cow libstore libmain nix-store nix-hash \
libexpr nix-instantiate nix-env nix-worker nix-setuid-helper \
nix-log2xml bsdiff-4.3 nix-state
EXTRA_DIST = aterm-helper.pl
SETUID_PROGS = nix-store nix-instantiate nix-env
install-exec-hook:
if SETUID_HACK
if HAVE_SETRESUID
cd $(DESTDIR)$(bindir) && chown @NIX_USER@ $(SETUID_PROGS) \
&& chgrp @NIX_GROUP@ $(SETUID_PROGS) && chmod ug+s $(SETUID_PROGS)
else
cd $(DESTDIR)$(bindir) && chown root $(SETUID_PROGS) && chmod u+s $(SETUID_PROGS)
endif
endif

View File

@@ -47,6 +47,7 @@ print HEADER "#endif\n\n\n";
print IMPL "namespace nix {\n";
while (<STDIN>) {
s/\#.*//;
next if (/^\s*$/);
if (/^\s*(\w*)\s*\|([^\|]*)\|\s*(\w+)\s*\|\s*(\w+)?/) {

View File

@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD: src/usr.bin/bsdiff/bspatch/bspatch.c,v 1.1 2005/08/06 01:59:
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
static off_t offtin(u_char *buf)
{

View File

@@ -2,11 +2,11 @@ pkglib_LTLIBRARIES = libexpr.la
libexpr_la_SOURCES = \
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
get-drvs.cc attr-path.cc expr-to-xml.cc
get-drvs.cc attr-path.cc expr-to-xml.cc common-opts.cc
pkginclude_HEADERS = \
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
get-drvs.hh attr-path.hh expr-to-xml.hh
get-drvs.hh attr-path.hh expr-to-xml.hh common-opts.hh
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
../boost/format/libformat.la

View File

@@ -46,7 +46,7 @@ Expr findAlongAttrPath(EvalState & state, const string & attrPath,
if (apType == apAttr) {
ATermMap attrs(128);
ATermMap attrs;
if (!isAttrs(state, e, attrs))
throw TypeError(

View File

@@ -0,0 +1,32 @@
#include "common-opts.hh"
#include "../libmain/shared.hh"
#include "util.hh"
#include "parser.hh"
namespace nix {
bool parseOptionArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state,
ATermMap & autoArgs)
{
if (arg != "--arg" && arg != "--argstr") return false;
UsageError error(format("`%1%' requires two arguments") % arg);
if (i == argsEnd) throw error;
string name = *i++;
if (i == argsEnd) throw error;
string value = *i++;
Expr e = arg == "--arg"
? parseExprFromString(state, value, absPath("."))
: makeStr(value);
autoArgs.set(toATerm(name), e);
return true;
}
}

View File

@@ -0,0 +1,17 @@
#ifndef __COMMON_OPTS_H
#define __COMMON_OPTS_H
#include "eval.hh"
namespace nix {
/* Some common option parsing between nix-env and nix-instantiate. */
bool parseOptionArg(const string & arg, Strings::iterator & i,
const Strings::iterator & argsEnd, EvalState & state,
ATermMap & autoArgs);
}
#endif /* !__COMMON_OPTS_H */

View File

@@ -2,8 +2,14 @@
#include "parser.hh"
#include "hash.hh"
#include "util.hh"
#include "store.hh"
#include "store-api.hh"
#include "derivations.hh"
#include "nixexpr-ast.hh"
#include "globals.hh"
#define LocalNoInline(f) static f __attribute__((noinline)); f
#define LocalNoInlineNoReturn(f) static f __attribute__((noinline, noreturn)); f
namespace nix {
@@ -27,6 +33,42 @@ void EvalState::addPrimOp(const string & name,
}
/* Every "format" object (even temporary) takes up a few hundred bytes
of stack space, which is a real killer in the recursive
evaluator. So here are some helper functions for throwing
exceptions. */
LocalNoInlineNoReturn(void throwEvalError(const char * s))
{
throw EvalError(s);
}
LocalNoInlineNoReturn(void throwEvalError(const char * s, const string & s2))
{
throw EvalError(format(s) % s2);
}
LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s2))
{
throw TypeError(format(s) % s2);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s))
{
e.addPrefix(s);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2))
{
e.addPrefix(format(s) % s2);
}
LocalNoInline(void addErrorPrefix(Error & e, const char * s, const string & s2, const string & s3))
{
e.addPrefix(format(s) % s2 % s3);
}
/* Substitute an argument set into the body of a function. */
static Expr substArgs(EvalState & state,
Expr body, ATermList formals, Expr arg)
@@ -35,7 +77,7 @@ static Expr substArgs(EvalState & state,
ATermMap subs(nrFormals);
/* Get the actual arguments and put them in the substitution. */
ATermMap args(128); /* !!! fix */
ATermMap args;
queryAllAttrs(arg, args);
for (ATermMap::const_iterator i = args.begin(); i != args.end(); ++i)
subs.set(i->key, i->value);
@@ -109,7 +151,7 @@ static Expr substArgs(EvalState & state,
to attributes substituted with selection expressions on the
original set. E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f
(e.x) (e.y); y = e.x;}'. */
ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds))
{
ATerm name;
Expr e2;
@@ -145,11 +187,11 @@ ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
}
static Expr updateAttrs(Expr e1, Expr e2)
LocalNoInline(Expr updateAttrs(Expr e1, Expr e2))
{
/* Note: e1 and e2 should be in normal form. */
ATermMap attrs(128); /* !!! */
ATermMap attrs;
queryAllAttrs(e1, attrs, true);
queryAllAttrs(e2, attrs, true);
@@ -157,23 +199,24 @@ static Expr updateAttrs(Expr e1, Expr e2)
}
string evalString(EvalState & state, Expr e)
string evalString(EvalState & state, Expr e, PathSet & context)
{
e = evalExpr(state, e);
ATerm s;
if (!matchStr(e, s))
throw TypeError(format("value is %1% while a string was expected") % showType(e));
return aterm2String(s);
string s;
if (!matchStr(e, s, context))
throwTypeError("value is %1% while a string was expected", showType(e));
return s;
}
Path evalPath(EvalState & state, Expr e)
string evalStringNoCtx(EvalState & state, Expr e)
{
e = evalExpr(state, e);
ATerm s;
if (!matchPath(e, s))
throw TypeError(format("value is %1% while a path was expected") % showType(e));
return aterm2String(s);
PathSet context;
string s = evalString(state, e, context);
if (!context.empty())
throw EvalError(format("the string `%1%' is not allowed to refer to a store path (such as `%2%')")
% s % *(context.begin()));
return s;
}
@@ -182,7 +225,7 @@ int evalInt(EvalState & state, Expr e)
e = evalExpr(state, e);
int i;
if (!matchInt(e, i))
throw TypeError(format("value is %1% while an integer was expected") % showType(e));
throwTypeError("value is %1% while an integer was expected", showType(e));
return i;
}
@@ -192,7 +235,7 @@ bool evalBool(EvalState & state, Expr e)
e = evalExpr(state, e);
if (e == eTrue) return true;
else if (e == eFalse) return false;
else throw TypeError(format("value is %1% while a boolean was expected") % showType(e));
else throwTypeError("value is %1% while a boolean was expected", showType(e));
}
@@ -201,110 +244,136 @@ ATermList evalList(EvalState & state, Expr e)
e = evalExpr(state, e);
ATermList list;
if (!matchList(e, list))
throw TypeError(format("value is %1% while a list was expected") % showType(e));
throwTypeError("value is %1% while a list was expected", showType(e));
return list;
}
/* String concatenation and context nodes: in order to allow users to
write things like
"--with-freetype2-library=" + freetype + "/lib"
where `freetype' is a derivation, we automatically coerce
derivations into their output path (e.g.,
/nix/store/hashcode-freetype) in concatenations. However, if we do
this naively, we could introduce an undeclared dependency: when the
string is used in another derivation, that derivation would not
have an explicitly dependency on `freetype' in its inputDrvs
field. Thus `freetype' would not necessarily be built.
To prevent this, we wrap the string resulting from the
concatenation in a *context node*, like this:
Context([freetype],
Str("--with-freetype2-library=/nix/store/hashcode-freetype/lib"))
Thus the context is the list of all derivations used in the
computation of a value. These contexts are propagated through
further concatenations. In processBinding() in primops.cc, context
nodes are unwrapped and added to inputDrvs.
!!! Should the ordering of the context list have a canonical form?
!!! Contexts are not currently recognised in most places in the
evaluator. */
/* Coerce a value to a string, keeping track of contexts. */
string coerceToStringWithContext(EvalState & state,
ATermList & context, Expr e, bool & isPath)
static void flattenList(EvalState & state, Expr e, ATermList & result)
{
ATermList es;
e = evalExpr(state, e);
if (matchList(e, es))
for (ATermIterator i(es); i; ++i)
flattenList(state, *i, result);
else
result = ATinsert(result, e);
}
ATermList flattenList(EvalState & state, Expr e)
{
ATermList result = ATempty;
flattenList(state, e, result);
return ATreverse(result);
}
string coerceToString(EvalState & state, Expr e, PathSet & context,
bool coerceMore, bool copyToStore)
{
isPath = false;
e = evalExpr(state, e);
string s;
if (matchStr(e, s, context)) return s;
ATerm s2;
if (matchPath(e, s2)) {
Path path(canonPath(aterm2String(s2)));
if (!copyToStore) return path;
if (isDerivation(path))
throw EvalError(format("file names are not allowed to end in `%1%'")
% drvExtension);
Path dstPath;
if (state.srcToStore[path] != "")
dstPath = state.srcToStore[path];
else {
dstPath = readOnlyMode
? computeStorePathForPath(path).first
: store->addToStore(path);
state.srcToStore[path] = dstPath;
printMsg(lvlChatty, format("copied source `%1%' -> `%2%'")
% path % dstPath);
}
context.insert(dstPath);
return dstPath;
}
ATermList es;
ATerm e2;
if (matchContext(e, es, e2)) {
e = e2;
context = ATconcat(es, context);
}
ATerm s;
if (matchStr(e, s) || matchUri(e, s))
return aterm2String(s);
if (matchPath(e, s)) {
isPath = true;
Path path = aterm2String(s);
if (isInStore(path)) {
context = ATinsert(context, makePath(toATerm(toStorePath(path))));
}
return path;
}
if (matchAttrs(e, es))
return coerceToString(state, makeSelect(e, toATerm("outPath")),
context, coerceMore, copyToStore);
if (matchAttrs(e, es)) {
ATermMap attrs(128); /* !!! */
queryAllAttrs(e, attrs, false);
if (coerceMore) {
Expr a = attrs.get(toATerm("type"));
if (a && evalString(state, a) == "derivation") {
a = attrs.get(toATerm("outPath"));
if (!a) throw TypeError("output path missing from derivation");
isPath = true;
context = ATinsert(context, e);
return evalPath(state, a);
/* Note that `false' is represented as an empty string for
shell scripting convenience, just like `null'. */
if (e == eTrue) return "1";
if (e == eFalse) return "";
int n;
if (matchInt(e, n)) return int2String(n);
if (matchNull(e)) return "";
if (matchList(e, es)) {
string result;
es = flattenList(state, e);
bool first = true;
for (ATermIterator i(es); i; ++i) {
if (!first) result += " "; else first = false;
result += coerceToString(state, *i,
context, coerceMore, copyToStore);
}
return result;
}
}
throw TypeError(format("cannot coerce %1% to a string") % showType(e));
throwTypeError("cannot coerce %1% to a string", showType(e));
}
/* Wrap an expression in a context if the context is not empty. */
Expr wrapInContext(ATermList context, Expr e)
/* Common implementation of `+', ConcatStrings and `~'. */
static ATerm concatStrings(EvalState & state, ATermVector & args,
string separator = "")
{
return context == ATempty ? e : makeContext(context, e);
}
static ATerm concatStrings(EvalState & state, const ATermVector & args)
{
ATermList context = ATempty;
if (args.empty()) return makeStr("", PathSet());
PathSet context;
std::ostringstream s;
bool isPath = false;
/* If the first element is a path, then the result will also be a
path, we don't copy anything (yet - that's done later, since
paths are copied when they are used in a derivation), and none
of the strings are allowed to have contexts. */
ATerm dummy;
args.front() = evalExpr(state, args.front());
bool isPath = matchPath(args.front(), dummy);
for (ATermVector::const_iterator i = args.begin(); i != args.end(); ++i) {
bool isPath2;
s << coerceToStringWithContext(state, context, *i, isPath2);
if (i == args.begin()) isPath = isPath2;
if (i != args.begin()) s << separator;
s << coerceToString(state, *i, context, false, !isPath);
}
Expr result = isPath
? makePath(toATerm(canonPath(s.str())))
: makeStr(toATerm(s.str()));
return wrapInContext(context, result);
if (isPath && !context.empty())
throw EvalError(format("a string that refers to a store path cannot be appended to a path, in `%1%'")
% s.str());
return isPath
? makePath(toATerm(s.str()))
: makeStr(s.str(), context);
}
Path coerceToPath(EvalState & state, Expr e, PathSet & context)
{
string path = coerceToString(state, e, context, false, false);
if (path == "" || path[0] != '/')
throw EvalError(format("string `%1%' doesn't represent an absolute path") % path);
return path;
}
@@ -314,7 +383,7 @@ Expr autoCallFunction(Expr e, const ATermMap & args)
ATerm body, pos;
if (matchFunction(e, formals, body, pos)) {
ATermMap actualArgs(128);
ATermMap actualArgs(ATgetLength(formals));
for (ATermIterator i(formals); i; ++i) {
Expr name, def, value; ATerm values, def2;
@@ -333,16 +402,233 @@ Expr autoCallFunction(Expr e, const ATermMap & args)
}
/* Evaluation of various language constructs. These have been taken
out of evalExpr2 to reduce stack space usage. (GCC is really dumb
about stack space: it just adds up all the local variables and
temporaries of every scope into one huge stack frame. This is
really bad for deeply recursive functions.) */
LocalNoInline(Expr evalVar(EvalState & state, ATerm name))
{
ATerm primOp = state.primOps.get(name);
if (!primOp)
throw EvalError(format("impossible: undefined variable `%1%'") % aterm2String(name));
int arity;
ATermBlob fun;
if (!matchPrimOpDef(primOp, arity, fun)) abort();
if (arity == 0)
/* !!! backtrace for primop call */
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
else
return makePrimOp(arity, fun, ATempty);
}
LocalNoInline(Expr evalCall(EvalState & state, Expr fun, Expr arg))
{
ATermList formals;
ATerm pos, name;
Expr body;
/* Evaluate the left-hand side. */
fun = evalExpr(state, fun);
/* Is it a primop or a function? */
int arity;
ATermBlob funBlob;
ATermList args;
if (matchPrimOp(fun, arity, funBlob, args)) {
args = ATinsert(args, arg);
if (ATgetLength(args) == arity) {
/* Put the arguments in a vector in reverse (i.e.,
actual) order. */
ATermVector args2(arity);
for (ATermIterator i(args); i; ++i)
args2[--arity] = *i;
/* !!! backtrace for primop call */
return ((PrimOp) ATgetBlobData(funBlob))
(state, args2);
} else
/* Need more arguments, so propagate the primop. */
return makePrimOp(arity, funBlob, args);
}
else if (matchFunction(fun, formals, body, pos)) {
arg = evalExpr(state, arg);
try {
return evalExpr(state, substArgs(state, body, formals, arg));
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n",
showPos(pos));
throw;
}
}
else if (matchFunction1(fun, name, body, pos)) {
try {
ATermMap subs(1);
subs.set(name, arg);
return evalExpr(state, substitute(Substitution(0, &subs), body));
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the function at %1%:\n",
showPos(pos));
throw;
}
}
else throwTypeError(
"attempt to call something which is neither a function nor a primop (built-in operation) but %1%",
showType(fun));
}
LocalNoInline(Expr evalSelect(EvalState & state, Expr e, ATerm name))
{
ATerm pos;
string s = aterm2String(name);
Expr a = queryAttr(evalExpr(state, e), s, pos);
if (!a) throwEvalError("attribute `%1%' missing", s);
try {
return evalExpr(state, a);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the attribute `%1%' at %2%:\n",
s, showPos(pos));
throw;
}
}
LocalNoInline(Expr evalAssert(EvalState & state, Expr cond, Expr body, ATerm pos))
{
if (!evalBool(state, cond))
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
return evalExpr(state, body);
}
LocalNoInline(Expr evalWith(EvalState & state, Expr defs, Expr body, ATerm pos))
{
ATermMap attrs;
try {
defs = evalExpr(state, defs);
queryAllAttrs(defs, attrs);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the `with' definitions at %1%:\n",
showPos(pos));
throw;
}
try {
body = substitute(Substitution(0, &attrs), body);
checkVarDefs(state.primOps, body);
return evalExpr(state, body);
} catch (Error & e) {
addErrorPrefix(e, "while evaluating the `with' body at %1%:\n",
showPos(pos));
throw;
}
}
LocalNoInline(Expr evalHasAttr(EvalState & state, Expr e, ATerm name))
{
ATermMap attrs;
queryAllAttrs(evalExpr(state, e), attrs);
return makeBool(attrs.get(name) != 0);
}
LocalNoInline(Expr evalPlusConcat(EvalState & state, Expr e))
{
Expr e1, e2;
ATermList es;
ATermVector args;
if (matchOpPlus(e, e1, e2)) {
/* !!! Awful compatibility hack for `drv + /path'.
According to regular concatenation, /path should be
copied to the store and its store path should be
appended to the string. However, in Nix <= 0.10, /path
was concatenated. So handle that case separately, but
do print out a warning. This code can go in Nix 0.12,
maybe. */
e1 = evalExpr(state, e1);
e2 = evalExpr(state, e2);
ATermList as;
ATerm p;
if (matchAttrs(e1, as) && matchPath(e2, p)) {
static bool haveWarned = false;
warnOnce(haveWarned, format(
"concatenation of a derivation and a path is deprecated; "
"you should write `drv + \"%1%\"' instead of `drv + %1%'")
% aterm2String(p));
PathSet context;
return makeStr(
coerceToString(state, makeSelect(e1, toATerm("outPath")), context)
+ aterm2String(p), context);
}
args.push_back(e1);
args.push_back(e2);
}
else if (matchConcatStrings(e, es))
for (ATermIterator i(es); i; ++i) args.push_back(*i);
try {
return concatStrings(state, args);
} catch (Error & e) {
addErrorPrefix(e, "in a string concatenation:\n");
throw;
}
}
LocalNoInline(Expr evalSubPath(EvalState & state, Expr e1, Expr e2))
{
static bool haveWarned = false;
warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead");
ATermVector args;
args.push_back(e1);
args.push_back(e2);
return concatStrings(state, args, "/");
}
LocalNoInline(Expr evalOpConcat(EvalState & state, Expr e1, Expr e2))
{
try {
ATermList l1 = evalList(state, e1);
ATermList l2 = evalList(state, e2);
return makeList(ATconcat(l1, l2));
} catch (Error & e) {
addErrorPrefix(e, "in a list concatenation:\n");
throw;
}
}
static char * deepestStack = (char *) -1; /* for measuring stack usage */
Expr evalExpr2(EvalState & state, Expr e)
{
Expr e1, e2, e3, e4;
/* When changing this function, make sure that you don't cause a
(large) increase in stack consumption! */
char x;
if (&x < deepestStack) deepestStack = &x;
Expr e1, e2, e3;
ATerm name, pos;
AFun sym = ATgetAFun(e);
/* Normal forms. */
if (sym == symStr ||
sym == symPath ||
sym == symUri ||
sym == symNull ||
sym == symInt ||
sym == symBool ||
@@ -350,8 +636,7 @@ Expr evalExpr2(EvalState & state, Expr e)
sym == symFunction1 ||
sym == symAttrs ||
sym == symList ||
sym == symPrimOp ||
sym == symContext)
sym == symPrimOp)
return e;
/* The `Closed' constructor is just a way to prevent substitutions
@@ -361,89 +646,13 @@ Expr evalExpr2(EvalState & state, Expr e)
/* Any encountered variables must be primops (since undefined
variables are detected after parsing). */
if (matchVar(e, name)) {
ATerm primOp = state.primOps.get(name);
if (!primOp)
throw EvalError(format("impossible: undefined variable `%1%'") % aterm2String(name));
int arity;
ATermBlob fun;
if (!matchPrimOpDef(primOp, arity, fun)) abort();
if (arity == 0)
return ((PrimOp) ATgetBlobData(fun)) (state, ATermVector());
else
return makePrimOp(arity, fun, ATempty);
}
if (matchVar(e, name)) return evalVar(state, name);
/* Function application. */
if (matchCall(e, e1, e2)) {
ATermList formals;
ATerm pos;
/* Evaluate the left-hand side. */
e1 = evalExpr(state, e1);
/* Is it a primop or a function? */
int arity;
ATermBlob fun;
ATermList args;
if (matchPrimOp(e1, arity, fun, args)) {
args = ATinsert(args, e2);
if (ATgetLength(args) == arity) {
/* Put the arguments in a vector in reverse (i.e.,
actual) order. */
ATermVector args2(arity);
for (ATermIterator i(args); i; ++i)
args2[--arity] = *i;
return ((PrimOp) ATgetBlobData((ATermBlob) fun))
(state, args2);
} else
/* Need more arguments, so propagate the primop. */
return makePrimOp(arity, fun, args);
}
else if (matchFunction(e1, formals, e4, pos)) {
e2 = evalExpr(state, e2);
try {
return evalExpr(state, substArgs(state, e4, formals, e2));
} catch (Error & e) {
e.addPrefix(format("while evaluating the function at %1%:\n")
% showPos(pos));
throw;
}
}
else if (matchFunction1(e1, name, e4, pos)) {
try {
ATermMap subs(1);
subs.set(name, e2);
return evalExpr(state, substitute(Substitution(0, &subs), e4));
} catch (Error & e) {
e.addPrefix(format("while evaluating the function at %1%:\n")
% showPos(pos));
throw;
}
}
else throw TypeError(
format("the left-hand side of the function call is neither a function nor a primop (built-in operation) but %1%")
% showType(e1));
}
if (matchCall(e, e1, e2)) return evalCall(state, e1, e2);
/* Attribute selection. */
if (matchSelect(e, e1, name)) {
ATerm pos;
string s1 = aterm2String(name);
Expr a = queryAttr(evalExpr(state, e1), s1, pos);
if (!a) throw EvalError(format("attribute `%1%' missing") % s1);
try {
return evalExpr(state, a);
} catch (Error & e) {
e.addPrefix(format("while evaluating the attribute `%1%' at %2%:\n")
% s1 % showPos(pos));
throw;
}
}
if (matchSelect(e, e1, name)) return evalSelect(state, e1, name);
/* Mutually recursive sets. */
ATermList rbnds, nrbnds;
@@ -451,41 +660,14 @@ Expr evalExpr2(EvalState & state, Expr e)
return expandRec(e, rbnds, nrbnds);
/* Conditionals. */
if (matchIf(e, e1, e2, e3)) {
if (evalBool(state, e1))
return evalExpr(state, e2);
else
return evalExpr(state, e3);
}
if (matchIf(e, e1, e2, e3))
return evalExpr(state, evalBool(state, e1) ? e2 : e3);
/* Assertions. */
if (matchAssert(e, e1, e2, pos)) {
if (!evalBool(state, e1))
throw AssertionError(format("assertion failed at %1%") % showPos(pos));
return evalExpr(state, e2);
}
if (matchAssert(e, e1, e2, pos)) return evalAssert(state, e1, e2, pos);
/* Withs. */
if (matchWith(e, e1, e2, pos)) {
ATermMap attrs(128); /* !!! */
try {
e1 = evalExpr(state, e1);
queryAllAttrs(e1, attrs);
} catch (Error & e) {
e.addPrefix(format("while evaluating the `with' definitions at %1%:\n")
% showPos(pos));
throw;
}
try {
e2 = substitute(Substitution(0, &attrs), e2);
checkVarDefs(state.primOps, e2);
return evalExpr(state, e2);
} catch (Error & e) {
e.addPrefix(format("while evaluating the `with' body at %1%:\n")
% showPos(pos));
throw;
}
}
if (matchWith(e, e1, e2, pos)) return evalWith(state, e1, e2, pos);
/* Generic equality/inequality. Note that the behaviour on
composite data (lists, attribute sets) and functions is
@@ -520,64 +702,31 @@ Expr evalExpr2(EvalState & state, Expr e)
return updateAttrs(evalExpr(state, e1), evalExpr(state, e2));
/* Attribute existence test (?). */
if (matchOpHasAttr(e, e1, name)) {
ATermMap attrs(128); /* !!! */
queryAllAttrs(evalExpr(state, e1), attrs);
return makeBool(attrs.get(name) != 0);
}
if (matchOpHasAttr(e, e1, name)) return evalHasAttr(state, e1, name);
/* String or path concatenation. */
ATermList es = ATempty;
if (matchOpPlus(e, e1, e2) || matchConcatStrings(e, es)) {
ATermVector args;
if (matchOpPlus(e, e1, e2)) {
args.push_back(e1);
args.push_back(e2);
} else
for (ATermIterator i(es); i; ++i) args.push_back(*i);
try {
return concatStrings(state, args);
} catch (Error & e) {
e.addPrefix(format("in a string concatenation:\n"));
throw;
}
}
if (sym == symOpPlus || sym == symConcatStrings)
return evalPlusConcat(state, e);
/* Backwards compatability: subpath operator (~). */
if (matchSubPath(e, e1, e2)) {
static bool haveWarned = false;
warnOnce(haveWarned, "the subpath operator (~) is deprecated, use string concatenation (+) instead");
ATermList context = ATempty;
bool dummy;
string s1 = coerceToStringWithContext(state, context, e1, dummy);
string s2 = coerceToStringWithContext(state, context, e2, dummy);
return wrapInContext(context, makePath(toATerm(canonPath(s1 + "/" + s2))));
}
if (matchSubPath(e, e1, e2)) return evalSubPath(state, e1, e2);
/* List concatenation. */
if (matchOpConcat(e, e1, e2)) {
try {
ATermList l1 = evalList(state, e1);
ATermList l2 = evalList(state, e2);
return makeList(ATconcat(l1, l2));
} catch (Error & e) {
e.addPrefix(format("in a list concatenation:\n"));
throw;
}
}
if (matchOpConcat(e, e1, e2)) return evalOpConcat(state, e1, e2);
/* Barf. */
throw badTerm("invalid expression", e);
abort();
}
Expr evalExpr(EvalState & state, Expr e)
{
checkInterrupt();
#if 0
startNest(nest, lvlVomit,
format("evaluating expression: %1%") % e);
#endif
state.nrEvaluated++;
@@ -586,7 +735,7 @@ Expr evalExpr(EvalState & state, Expr e)
Expr nf = state.normalForms.get(e);
if (nf) {
if (nf == makeBlackHole())
throw EvalError("infinite recursion encountered");
throwEvalError("infinite recursion encountered");
state.nrCached++;
return nf;
}
@@ -596,7 +745,6 @@ Expr evalExpr(EvalState & state, Expr e)
try {
nf = evalExpr2(state, e);
} catch (Error & err) {
debug("removing black hole");
state.normalForms.remove(e);
throw;
}
@@ -619,7 +767,10 @@ Expr evalFile(EvalState & state, const Path & path)
}
Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs);
static Expr strictEvalExpr_(EvalState & state, Expr e, ATermMap & nfs)
{
e = evalExpr(state, e);
@@ -629,10 +780,8 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
for (ATermIterator i(as); i; ++i) {
ATerm name; Expr e; ATerm pos;
if (!matchBind(*i, name, e, pos)) abort(); /* can't happen */
as2 = ATinsert(as2, makeBind(name, strictEvalExpr(state, e, canonicalise),
canonicalise ? makeNoPos() : pos));
as2 = ATinsert(as2, makeBind(name, strictEvalExpr(state, e, nfs), pos));
}
/* !!! sort attributes if canonicalise == true */
return makeAttrs(ATreverse(as2));
}
@@ -640,7 +789,7 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
if (matchList(e, es)) {
ATermList es2 = ATempty;
for (ATermIterator i(es); i; ++i)
es2 = ATinsert(es2, strictEvalExpr(state, *i, canonicalise));
es2 = ATinsert(es2, strictEvalExpr(state, *i, nfs));
return makeList(ATreverse(es2));
}
@@ -657,20 +806,40 @@ Expr strictEvalExpr(EvalState & state, Expr e, bool canonicalise)
if (matchValidValues(valids, valids2)) {
ATermList valids3 = ATempty;
for (ATermIterator j(valids2); j; ++j)
valids3 = ATinsert(valids3, strictEvalExpr(state, *j, canonicalise));
valids3 = ATinsert(valids3, strictEvalExpr(state, *j, nfs));
valids = makeValidValues(ATreverse(valids3));
}
formals2 = ATinsert(formals2, makeFormal(name, valids, dummy));
}
return makeFunction(ATreverse(formals2), body,
canonicalise ? makeNoPos() : pos);
return makeFunction(ATreverse(formals2), body, pos);
}
return e;
}
static Expr strictEvalExpr(EvalState & state, Expr e, ATermMap & nfs)
{
Expr nf = nfs.get(e);
if (nf) return nf;
nf = strictEvalExpr_(state, e, nfs);
nfs.set(e, nf);
return nf;
}
Expr strictEvalExpr(EvalState & state, Expr e)
{
ATermMap strictNormalForms;
return strictEvalExpr(state, e, strictNormalForms);
}
/* Yes, this is a really bad idea... */
extern "C" {
unsigned long AT_calcAllocatedSize();
@@ -678,12 +847,14 @@ extern "C" {
void printEvalStats(EvalState & state)
{
char x;
bool showStats = getEnv("NIX_SHOW_STATS", "0") != "0";
printMsg(showStats ? lvlInfo : lvlDebug,
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes")
format("evaluated %1% expressions, %2% cache hits, %3%%% efficiency, used %4% ATerm bytes, used %5% bytes of stack space")
% state.nrEvaluated % state.nrCached
% ((float) state.nrCached / (float) state.nrEvaluated * 100)
% AT_calcAllocatedSize());
% AT_calcAllocatedSize()
% (&x - deepestStack));
if (showStats)
printATermMapStats();
}

View File

@@ -16,7 +16,7 @@ class Hash;
typedef std::map<Path, PathSet> DrvRoots;
typedef std::map<Path, Hash> DrvHashes;
/* Cache for calls to addToStore(); maps source paths to the store
/* Cache for calls to addToStore(); maps source paths to the store //THIS OK ????
paths. */
typedef std::map<Path, Path> SrcToStore;
@@ -56,21 +56,29 @@ Expr evalFile(EvalState & state, const Path & path);
attributes. If `canonicalise' is true, we remove things like
position information and make sure that attribute sets are in
sorded order. */
Expr strictEvalExpr(EvalState & state, Expr e,
bool canonicalise = false);
Expr strictEvalExpr(EvalState & state, Expr e);
/* Specific results. */
string evalString(EvalState & state, Expr e);
Path evalPath(EvalState & state, Expr e);
string evalString(EvalState & state, Expr e, PathSet & context);
string evalStringNoCtx(EvalState & state, Expr e);
int evalInt(EvalState & state, Expr e);
bool evalBool(EvalState & state, Expr e);
ATermList evalList(EvalState & state, Expr e);
ATerm coerceToString(Expr e);
/* Contexts. */
string coerceToStringWithContext(EvalState & state,
ATermList & context, Expr e, bool & isPath);
Expr wrapInContext(ATermList context, Expr e);
/* Flatten nested lists into a single list (or expand a singleton into
a list). */
ATermList flattenList(EvalState & state, Expr e);
/* String coercion. Converts strings, paths and derivations to a
string. If `coerceMore' is set, also converts nulls, integers,
booleans and lists to a string. */
string coerceToString(EvalState & state, Expr e, PathSet & context,
bool coerceMore = false, bool copyToStore = true);
/* Path coercion. Converts strings, paths and derivations to a path.
The result is guaranteed to be an canonicalised, absolute path.
Nothing is copied to the store. */
Path coerceToPath(EvalState & state, Expr e, PathSet & context);
/* Automatically call a function for which each argument has a default
value or has a binding in the `args' map. Note: result is a call,

View File

@@ -2,6 +2,7 @@
#include "xml-writer.hh"
#include "nixexpr-ast.hh"
#include "aterm.hh"
#include "util.hh"
namespace nix {
@@ -15,29 +16,45 @@ static XMLAttrs singletonAttrs(const string & name, const string & value)
}
static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
/* set<Expr> is safe because all the expressions are also reachable
from the stack, therefore can't be garbage-collected. */
typedef set<Expr> ExprSet;
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
ExprSet & drvsSeen);
static void showAttrs(const ATermMap & attrs, XMLWriter & doc,
PathSet & context, ExprSet & drvsSeen)
{
StringSet names;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
names.insert(aterm2String(i->key));
for (StringSet::iterator i = names.begin(); i != names.end(); ++i) {
XMLOpenElement _(doc, "attr", singletonAttrs("name", *i));
printTermAsXML(attrs.get(toATerm(*i)), doc, context, drvsSeen);
}
}
static void printTermAsXML(Expr e, XMLWriter & doc, PathSet & context,
ExprSet & drvsSeen)
{
XMLAttrs attrs;
ATerm s;
string s;
ATerm s2;
int i;
Expr e2;
ATermList as, es, formals;
ATerm body, pos;
while (matchContext(e, es, e2)) {
e = e2;
for (ATermIterator i(es); i; ++i)
context = ATinsert(context, *i);
}
checkInterrupt();
if (matchStr(e, s))
doc.writeEmptyElement("string", singletonAttrs("value", aterm2String(s)));
if (matchStr(e, s, context)) /* !!! show the context? */
doc.writeEmptyElement("string", singletonAttrs("value", s));
else if (matchPath(e, s))
doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s)));
else if (matchUri(e, s))
doc.writeEmptyElement("uri", singletonAttrs("value", aterm2String(s)));
else if (matchPath(e, s2))
doc.writeEmptyElement("path", singletonAttrs("value", aterm2String(s2)));
else if (matchNull(e))
doc.writeEmptyElement("null");
@@ -52,22 +69,42 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
doc.writeEmptyElement("bool", singletonAttrs("value", "false"));
else if (matchAttrs(e, as)) {
XMLOpenElement _(doc, "attrs");
ATermMap attrs(128);
ATermMap attrs;
queryAllAttrs(e, attrs);
StringSet names;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
names.insert(aterm2String(i->key));
for (StringSet::iterator i = names.begin(); i != names.end(); ++i) {
XMLOpenElement _(doc, "attr", singletonAttrs("name", *i));
printTermAsXML(attrs.get(toATerm(*i)), doc, context);
Expr a = attrs.get(toATerm("type"));
if (a && matchStr(a, s, context) && s == "derivation") {
XMLAttrs xmlAttrs;
Path outPath, drvPath;
a = attrs.get(toATerm("drvPath"));
if (matchStr(a, drvPath, context))
xmlAttrs["drvPath"] = drvPath;
a = attrs.get(toATerm("outPath"));
if (matchStr(a, outPath, context))
xmlAttrs["outPath"] = outPath;
XMLOpenElement _(doc, "derivation", xmlAttrs);
if (drvsSeen.find(e) == drvsSeen.end()) {
drvsSeen.insert(e);
showAttrs(attrs, doc, context, drvsSeen);
} else
doc.writeEmptyElement("repeated");
}
else {
XMLOpenElement _(doc, "attrs");
showAttrs(attrs, doc, context, drvsSeen);
}
}
else if (matchList(e, es)) {
XMLOpenElement _(doc, "list");
for (ATermIterator i(es); i; ++i)
printTermAsXML(*i, doc, context);
printTermAsXML(*i, doc, context, drvsSeen);
}
else if (matchFunction(e, formals, body, pos)) {
@@ -82,7 +119,7 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
if (matchValidValues(valids, valids2)) {
for (ATermIterator j(valids2); j; ++j) {
XMLOpenElement _(doc, "value");
printTermAsXML(*j, doc, context);
printTermAsXML(*j, doc, context, drvsSeen);
}
}
}
@@ -93,11 +130,12 @@ static void printTermAsXML(Expr e, XMLWriter & doc, ATermList & context)
}
void printTermAsXML(Expr e, std::ostream & out, ATermList & context)
void printTermAsXML(Expr e, std::ostream & out, PathSet & context)
{
XMLWriter doc(true, out);
XMLOpenElement root(doc, "expr");
printTermAsXML(e, doc, context);
ExprSet drvsSeen;
printTermAsXML(e, doc, context, drvsSeen);
}

View File

@@ -9,7 +9,7 @@
namespace nix {
void printTermAsXML(Expr e, std::ostream & out, ATermList & context);
void printTermAsXML(Expr e, std::ostream & out, PathSet & context);
}

View File

@@ -10,7 +10,15 @@ string DrvInfo::queryDrvPath(EvalState & state) const
{
if (drvPath == "") {
Expr a = attrs->get(toATerm("drvPath"));
(string &) drvPath = a ? evalPath(state, a) : "";
/* Backwards compatibility hack with user environments made by
Nix <= 0.10: these contain illegal Path("") expressions. */
ATerm t;
if (a && matchPath(evalExpr(state, a), t))
return aterm2String(t);
PathSet context;
(string &) drvPath = a ? coerceToPath(state, a, context) : "";
}
return drvPath;
}
@@ -21,11 +29,59 @@ string DrvInfo::queryOutPath(EvalState & state) const
if (outPath == "") {
Expr a = attrs->get(toATerm("outPath"));
if (!a) throw TypeError("output path missing");
(string &) outPath = evalPath(state, a);
PathSet context;
(string &) outPath = coerceToPath(state, a, context);
}
return outPath;
}
string DrvInfo::queryStateIdentifier(EvalState & state) const
{
if (stateIdentifier == "") {
ATermMap attrs2 = *attrs;
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
string key = (string)aterm2String(i->key); //cast because aterm2String returns a char*
//printMsg(lvlError, format("ATTR2: '%1%'") % key);
if(key == "stateIdentifier"){
PathSet context;
string value = coerceToString(state, i->value, context);
(string &) stateIdentifier = value;
}
}
//If still empty
if (trim(stateIdentifier) == "")
(string &) stateIdentifier = "__NOSTATE__";
}
return stateIdentifier;
}
string DrvInfo::queryRuntimeStateArgs(EvalState & state) const
{
if (runtimeStateArgs == "") {
ATermMap attrs2 = *attrs;
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
string key = (string)aterm2String(i->key); //cast because aterm2String returns a char*
if(key == "runtimeStateArgs"){
PathSet context;
string value = coerceToString(state, i->value, context);
(string &) runtimeStateArgs = value;
}
}
//If still empty
if (trim(runtimeStateArgs) == "")
(string &) runtimeStateArgs = "__NOARGS__";
}
return runtimeStateArgs;
}
MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
{
@@ -34,13 +90,15 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
Expr a = attrs->get(toATerm("meta"));
if (!a) return meta; /* fine, empty meta information */
ATermMap attrs2(16); /* !!! */
ATermMap attrs2;
queryAllAttrs(evalExpr(state, a), attrs2);
for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
ATerm s = coerceToString(evalExpr(state, i->value));
if (s)
meta[aterm2String(i->key)] = aterm2String(s);
Expr e = evalExpr(state, i->value);
string s;
PathSet context;
if (matchStr(e, s, context))
meta[aterm2String(i->key)] = s;
/* For future compatibility, ignore attribute values that are
not strings. */
}
@@ -49,6 +107,25 @@ MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
}
string DrvInfo::queryMetaInfo(EvalState & state, const string & name) const
{
/* !!! evaluates all meta attributes => inefficient */
MetaInfo meta = queryMetaInfo(state);
MetaInfo::iterator i = meta.find(name);
return i == meta.end() ? "" : i->second;
}
void DrvInfo::setMetaInfo(const MetaInfo & meta)
{
ATermMap metaAttrs;
for (MetaInfo::const_iterator i = meta.begin(); i != meta.end(); ++i)
metaAttrs.set(toATerm(i->first),
makeAttrRHS(makeStr(i->second), makeNoPos()));
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
}
/* Cache for already evaluated derivations. Usually putting ATerms in
a STL container is unsafe (they're not scanning for GC roots), but
here it doesn't matter; everything in this set is reachable from
@@ -70,32 +147,37 @@ static bool getDerivation(EvalState & state, Expr e,
e = evalExpr(state, e);
if (!matchAttrs(e, es)) return true;
boost::shared_ptr<ATermMap> attrs(new ATermMap(32)); /* !!! */
boost::shared_ptr<ATermMap> attrs(new ATermMap());
queryAllAttrs(e, *attrs, false);
Expr a = attrs->get(toATerm("type"));
if (!a || evalString(state, a) != "derivation") return true;
if (!a || evalStringNoCtx(state, a) != "derivation")
return true;
/* Remove spurious duplicates (e.g., an attribute set like
`rec { x = derivation {...}; y = x;}'. */
if (doneExprs.find(e) != doneExprs.end()) return false;
if (doneExprs.find(e) != doneExprs.end())
return false;
doneExprs.insert(e);
DrvInfo drv;
a = attrs->get(toATerm("name"));
/* !!! We really would like to have a decent back trace here. */
if (!a) throw TypeError("derivation name missing");
drv.name = evalString(state, a);
if (!a)
throw TypeError("derivation name missing");
drv.name = evalStringNoCtx(state, a);
a = attrs->get(toATerm("system"));
if (!a)
drv.system = "unknown";
else
drv.system = evalString(state, a);
drv.system = evalStringNoCtx(state, a);
drv.attrs = attrs;
//printMsg(lvlError, format("TEST '%1%'") % evalStringNoCtx(state, a) );
drv.attrPath = attrPath;
drvs.push_back(drv);
@@ -112,7 +194,8 @@ bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
Exprs doneExprs;
DrvInfos drvs;
getDerivation(state, e, "", drvs, doneExprs);
if (drvs.size() != 1) return false;
if (drvs.size() != 1)
return false;
drv = drvs.front();
return true;
}
@@ -140,12 +223,21 @@ static void getDerivations(EvalState & state, Expr e,
if (matchAttrs(e, es)) {
ATermMap drvMap(ATgetLength(es));
queryAllAttrs(e, drvMap);
/* !!! undocumented hackery to support combining channels in
nix-env.cc. */
Expr e2 = drvMap.get(toATerm("_combineChannels"));
bool combineChannels = e2 && evalBool(state, e2);
for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
startNest(nest, lvlDebug,
format("evaluating attribute `%1%'") % aterm2String(i->key));
string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key));
if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
if (combineChannels) {
if (((string) aterm2String(i->key)) != "_combineChannels")
getDerivations(state, i->value, pathPrefix2, autoArgs, drvs, doneExprs);
}
else if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
/* If the value of this attribute is itself an
attribute set, should we recurse into it? => Only
if it has a `recurseForDerivations = true'
@@ -155,8 +247,8 @@ static void getDerivations(EvalState & state, Expr e,
if (matchAttrs(e, es)) {
ATermMap attrs(ATgetLength(es));
queryAllAttrs(e, attrs, false);
Expr e2 = attrs.get(toATerm("recurseForDerivations"));
if (e2 && evalBool(state, e2))
if (((e2 = attrs.get(toATerm("recurseForDerivations")))
&& evalBool(state, e2)))
getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
}
}

View File

@@ -20,17 +20,25 @@ struct DrvInfo
private:
string drvPath;
string outPath;
string stateIdentifier;
string runtimeStateArgs;
public:
string name;
string attrPath; /* path towards the derivation */
string system;
/* !!! these should really be hidden, and setMetaInfo() should
make a copy since the ATermMap can be shared between multiple
DrvInfos. */
boost::shared_ptr<ATermMap> attrs;
string queryDrvPath(EvalState & state) const;
string queryOutPath(EvalState & state) const;
string queryStateIdentifier(EvalState & state) const;
string queryRuntimeStateArgs(EvalState & state) const;
MetaInfo queryMetaInfo(EvalState & state) const;
string queryMetaInfo(EvalState & state, const string & name) const;
void setDrvPath(const string & s)
{
@@ -41,6 +49,18 @@ public:
{
outPath = s;
}
void setStateIdentifier(const string & s)
{
stateIdentifier = s;
}
void setRuntimeStateArgs(const string & s)
{
runtimeStateArgs = s;
}
void setMetaInfo(const MetaInfo & meta);
};

View File

@@ -4,6 +4,7 @@
%x STRING
%x IND_STRING
%{
@@ -64,7 +65,7 @@ static Expr unescapeStr(const char * s)
}
else t += c;
}
return makeStr(toATerm(t));
return makeStr(toATerm(t), ATempty);
}
@@ -122,6 +123,30 @@ inherit { return INHERIT; }
<STRING>\" { BEGIN(INITIAL); return '"'; }
<STRING>. return yytext[0]; /* just in case: shouldn't be reached */
\'\'(\ *\n)? { BEGIN(IND_STRING); return IND_STRING_OPEN; }
<IND_STRING>([^\$\']|\$[^\{\']|\'[^\'\$])+ {
yylval->t = makeIndStr(toATerm(yytext));
return IND_STR;
}
<IND_STRING>\'\'\$ {
yylval->t = makeIndStr(toATerm("$"));
return IND_STR;
}
<IND_STRING>\'\'\' {
yylval->t = makeIndStr(toATerm("''"));
return IND_STR;
}
<IND_STRING>\'\'\\. {
yylval->t = unescapeStr(yytext + 2);
return IND_STR;
}
<IND_STRING>\$\{ { BEGIN(INITIAL); return DOLLAR_CURLY; }
<IND_STRING>\'\' { BEGIN(INITIAL); return IND_STRING_CLOSE; }
<IND_STRING>\' {
yylval->t = makeIndStr(toATerm("'"));
return IND_STR;
}
<IND_STRING>. return yytext[0]; /* just in case: shouldn't be reached */
{PATH} { yylval->t = toATerm(yytext); return PATH; /* !!! alloc */ }
{URI} { yylval->t = toATerm(yytext); return URI; /* !!! alloc */ }
@@ -148,4 +173,10 @@ void backToString(yyscan_t scanner)
BEGIN(STRING);
}
void backToIndString(yyscan_t scanner)
{
struct yyguts_t * yyg = (struct yyguts_t *) scanner;
BEGIN(IND_STRING);
}
}

View File

@@ -24,9 +24,41 @@ Call | Expr Expr | Expr |
Select | Expr string | Expr |
Var | string | Expr |
Int | int | Expr |
Str | string | Expr |
# Strings in the evaluator carry a so-called `context' (the ATermList)
# which is a list of strings representing store paths. This is to
# allow users to write things like
#
# "--with-freetype2-library=" + freetype + "/lib"
#
# where `freetype' is a derivation (or a source to be copied to the
# store). If we just concatenated the strings without keeping track
# of the referenced store paths, then if the string is used as a
# derivation attribute, the derivation will not have the correct
# dependencies in its inputDrvs and inputSrcs.
#
# The semantics of the context is as follows: when a string with
# context C is used as a derivation attribute, then the derivations in
# C will be added to the inputDrvs of the derivation, and the other
# store paths in C will be added to the inputSrcs of the derivations.
#
# For canonicity, the store paths should be in sorted order.
Str | string ATermList | Expr |
Str | string | Expr | ObsoleteStr
# Internal to the parser, doesn't occur in ASTs.
IndStr | string | Expr |
# A path is a reference to a file system object that is to be copied
# to the Nix store when used as a derivation attribute. When it is
# concatenated to a string (i.e., `str + path'), it is also copied and
# the resulting store path is concatenated to the string (with the
# store path in the context). If a string or path is concatenated to
# a path (i.e., `path + str' or `path + path'), the result is a new
# path (if the right-hand side is a string, the context must be
# empty).
Path | string | Expr |
Uri | string | Expr |
List | ATermList | Expr |
BlackHole | | Expr |
Undefined | | Expr |
@@ -37,10 +69,9 @@ Closed | Expr | Expr |
Rec | ATermList ATermList | Expr |
Bool | ATerm | Expr |
Null | | Expr |
Context | ATermList Expr | Expr |
Bind | string Expr Pos | ATerm |
Bind | string Expr | ATerm | Bind2
Bind | string Expr | ATerm | ObsoleteBind
Inherit | Expr ATermList Pos | ATerm |
Scope | | Expr |

View File

@@ -54,7 +54,7 @@ void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos)
{
ATermList bnds;
if (!matchAttrs(e, bnds))
throw TypeError("attribute set expected");
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
for (ATermIterator i(bnds); i; ++i) {
ATerm name;
@@ -77,7 +77,7 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos)
{
ATermList bnds;
if (!matchAttrs(e, bnds))
throw TypeError("attribute set expected");
throw TypeError(format("value is %1% while an attribute set was expected") % showType(e));
for (ATermIterator i(bnds); i; ++i) {
ATerm name2, pos2;
@@ -215,7 +215,11 @@ static void checkVarDefs2(set<Expr> & done, const ATermMap & defs, Expr e)
ATerm with, body;
ATermList rbnds, nrbnds;
if (matchVar(e, name)) {
/* Closed terms don't have free variables, so we don't have to
check by definition. */
if (matchClosed(e, value)) return;
else if (matchVar(e, name)) {
if (!defs.get(name))
throw EvalError(format("undefined variable `%1%'")
% aterm2String(name));
@@ -287,21 +291,81 @@ void checkVarDefs(const ATermMap & defs, Expr e)
}
struct Canonicalise : TermFun
{
ATerm operator () (ATerm e)
{
/* Remove position info. */
ATerm path;
int line, column;
if (matchPos(e, path, line, column))
return makeNoPos();
/* Sort attribute sets. */
ATermList _;
if (matchAttrs(e, _)) {
ATermMap attrs;
queryAllAttrs(e, attrs);
StringSet names;
for (ATermMap::const_iterator i = attrs.begin(); i != attrs.end(); ++i)
names.insert(aterm2String(i->key));
ATermList attrs2 = ATempty;
for (StringSet::reverse_iterator i = names.rbegin(); i != names.rend(); ++i)
attrs2 = ATinsert(attrs2,
makeBind(toATerm(*i), attrs.get(toATerm(*i)), makeNoPos()));
return makeAttrs(attrs2);
}
return e;
}
};
Expr canonicaliseExpr(Expr e)
{
Canonicalise canonicalise;
return bottomupRewrite(canonicalise, e);
}
Expr makeBool(bool b)
{
return b ? eTrue : eFalse;
}
bool matchStr(Expr e, string & s, PathSet & context)
{
ATermList l;
ATerm s_;
if (!matchStr(e, s_, l)) return false;
s = aterm2String(s_);
for (ATermIterator i(l); i; ++i)
context.insert(aterm2String(*i));
return true;
}
Expr makeStr(const string & s, const PathSet & context)
{
return makeStr(toATerm(s), toATermList(context));
}
string showType(Expr e)
{
ATerm t1, t2, t3;
ATermList l1;
ATermBlob b1;
int i1;
if (matchStr(e, t1)) return "a string";
if (matchStr(e, t1, l1)) return "a string";
if (matchPath(e, t1)) return "a path";
if (matchUri(e, t1)) return "a path";
if (matchNull(e)) return "null";
if (matchInt(e, i1)) return "an integer";
if (matchBool(e, t1)) return "a boolean";
@@ -310,18 +374,19 @@ string showType(Expr e)
if (matchAttrs(e, l1)) return "an attribute set";
if (matchList(e, l1)) return "a list";
if (matchPrimOp(e, i1, b1, l1)) return "a partially applied built-in function";
if (matchContext(e, l1, t1)) return "a context containing " + showType(t1);
return "an unknown type";
}
string showValue(Expr e)
{
ATerm s;
PathSet context;
string s;
ATerm s2;
int i;
if (matchStr(e, s)) {
string t = aterm2String(s), u;
for (string::iterator i = t.begin(); i != t.end(); ++i)
if (matchStr(e, s, context)) {
string u;
for (string::iterator i = s.begin(); i != s.end(); ++i)
if (*i == '\"' || *i == '\\') u += "\\" + *i;
else if (*i == '\n') u += "\\n";
else if (*i == '\r') u += "\\r";
@@ -329,8 +394,7 @@ string showValue(Expr e)
else u += *i;
return "\"" + u + "\"";
}
if (matchPath(e, s)) return aterm2String(s);
if (matchUri(e, s)) return aterm2String(s);
if (matchPath(e, s2)) return aterm2String(s2);
if (matchNull(e)) return "null";
if (matchInt(e, i)) return (format("%1%") % i).str();
if (e == eTrue) return "true";

View File

@@ -12,6 +12,7 @@ namespace nix {
MakeError(EvalError, Error)
MakeError(AssertionError, EvalError)
MakeError(ThrownError, AssertionError)
MakeError(Abort, EvalError)
MakeError(TypeError, EvalError)
@@ -71,6 +72,7 @@ struct TermFun
};
ATerm bottomupRewrite(TermFun & f, ATerm e);
/* Query all attributes in an attribute set expression. The
expression must be in normal form. */
void queryAllAttrs(Expr e, ATermMap & attrs, bool withPos = false);
@@ -83,16 +85,33 @@ Expr queryAttr(Expr e, const string & name, ATerm & pos);
/* Create an attribute set expression from an Attrs value. */
Expr makeAttrs(const ATermMap & attrs);
/* Perform a set of substitutions on an expression. */
Expr substitute(const Substitution & subs, Expr e);
/* Check whether all variables are defined in the given expression.
Throw an exception if this isn't the case. */
void checkVarDefs(const ATermMap & def, Expr e);
/* Canonicalise a Nix expression by sorting attributes and removing
location information. */
Expr canonicaliseExpr(Expr e);
/* Create an expression representing a boolean. */
Expr makeBool(bool b);
/* Manipulation of Str() nodes. Note: matchStr() does not clear
context! */
bool matchStr(Expr e, string & s, PathSet & context);
Expr makeStr(const string & s, const PathSet & context = PathSet());
/* Showing types, values. */
string showType(Expr e);
string showValue(Expr e);

View File

@@ -3,7 +3,7 @@
%locations
%error-verbose
%defines
%no-lines
/* %no-lines */
%parse-param { yyscan_t scanner }
%parse-param { ParseData * data }
%lex-param { yyscan_t scanner }
@@ -68,9 +68,100 @@ static Expr fixAttrs(int recursive, ATermList as)
}
void backToString(yyscan_t scanner);
static Expr stripIndentation(ATermList es)
{
if (es == ATempty) return makeStr("");
/* Figure out the minimum indentation. Note that by design
whitespace-only final lines are not taken into account. (So
the " " in "\n ''" is ignored, but the " " in "\n foo''" is.) */
bool atStartOfLine = true; /* = seen only whitespace in the current line */
unsigned int minIndent = 1000000;
unsigned int curIndent = 0;
ATerm e;
for (ATermIterator i(es); i; ++i) {
if (!matchIndStr(*i, e)) {
/* Anti-quotations end the current start-of-line whitespace. */
if (atStartOfLine) {
atStartOfLine = false;
if (curIndent < minIndent) minIndent = curIndent;
}
continue;
}
string s = aterm2String(e);
for (unsigned int j = 0; j < s.size(); ++j) {
if (atStartOfLine) {
if (s[j] == ' ')
curIndent++;
else if (s[j] == '\n') {
/* Empty line, doesn't influence minimum
indentation. */
curIndent = 0;
} else {
atStartOfLine = false;
if (curIndent < minIndent) minIndent = curIndent;
}
} else if (s[j] == '\n') {
atStartOfLine = true;
curIndent = 0;
}
}
}
/* Strip spaces from each line. */
ATermList es2 = ATempty;
atStartOfLine = true;
unsigned int curDropped = 0;
unsigned int n = ATgetLength(es);
for (ATermIterator i(es); i; ++i, --n) {
if (!matchIndStr(*i, e)) {
atStartOfLine = false;
curDropped = 0;
es2 = ATinsert(es2, *i);
continue;
}
string s = aterm2String(e);
string s2;
for (unsigned int j = 0; j < s.size(); ++j) {
if (atStartOfLine) {
if (s[j] == ' ') {
if (curDropped++ >= minIndent)
s2 += s[j];
}
else if (s[j] == '\n') {
curDropped = 0;
s2 += s[j];
} else {
atStartOfLine = false;
curDropped = 0;
s2 += s[j];
}
} else {
s2 += s[j];
if (s[j] == '\n') atStartOfLine = true;
}
}
/* Remove the last line if it is empty and consists only of
spaces. */
if (n == 1) {
unsigned int p = s2.find_last_of('\n');
if (p != string::npos && s2.find_first_not_of(' ', p + 1) == string::npos)
s2 = string(s2, 0, p + 1);
}
es2 = ATinsert(es2, makeStr(s2));
}
return makeConcatStrings(ATreverse(es2));
}
void backToString(yyscan_t scanner);
void backToIndString(yyscan_t scanner);
static Pos makeCurPos(YYLTYPE * loc, ParseData * data)
{
return makePos(toATerm(data->path),
@@ -121,10 +212,11 @@ static void freeAndUnprotect(void * p)
%type <t> start expr expr_function expr_if expr_op
%type <t> expr_app expr_select expr_simple bind inheritsrc formal
%type <ts> binds ids expr_list formals string_parts
%token <t> ID INT STR PATH URI
%type <ts> binds ids expr_list formals string_parts ind_string_parts
%token <t> ID INT STR IND_STR PATH URI
%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
%token DOLLAR_CURLY /* == ${ */
%token IND_STRING_OPEN IND_STRING_CLOSE
%nonassoc IMPL
%left OR
@@ -195,12 +287,15 @@ expr_simple
| INT { $$ = makeInt(ATgetInt((ATermInt) $1)); }
| '"' string_parts '"' {
/* For efficiency, and to simplify parse trees a bit. */
if ($2 == ATempty) $$ = makeStr(toATerm(""));
if ($2 == ATempty) $$ = makeStr(toATerm(""), ATempty);
else if (ATgetNext($2) == ATempty) $$ = ATgetFirst($2);
else $$ = makeConcatStrings(ATreverse($2));
}
| IND_STRING_OPEN ind_string_parts IND_STRING_CLOSE {
$$ = stripIndentation(ATreverse($2));
}
| PATH { $$ = makePath(toATerm(absPath(aterm2String($1), data->basePath))); }
| URI { $$ = makeUri($1); }
| URI { $$ = makeStr($1, ATempty); }
| '(' expr ')' { $$ = $2; }
/* Let expressions `let {..., body = ...}' are just desugared
into `(rec {..., body = ...}).body'. */
@@ -219,6 +314,12 @@ string_parts
| { $$ = ATempty; }
;
ind_string_parts
: ind_string_parts IND_STR { $$ = ATinsert($1, $2); }
| ind_string_parts DOLLAR_CURLY expr '}' { backToIndString(scanner); $$ = ATinsert($1, $3); }
| { $$ = ATempty; }
;
binds
: binds bind { $$ = ATinsert($1, $2); }
| { $$ = ATempty; }
@@ -249,6 +350,7 @@ expr_list
formals
: formal ',' formals { $$ = ATinsert($3, $1); } /* idem - right recursive */
| formal { $$ = ATinsert(ATempty, $1); }
| { $$ = ATempty; }
;
formal
@@ -358,8 +460,6 @@ static Expr parse(EvalState & state,
Expr parseExprFromFile(EvalState & state, Path path)
{
SwitchToOriginalUser sw;
assert(path[0] == '/');
#if 0
@@ -371,9 +471,12 @@ Expr parseExprFromFile(EvalState & state, Path path)
/* If `path' is a symlink, follow it. This is so that relative
path references work. */
struct stat st;
if (lstat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path);
if (S_ISLNK(st.st_mode)) path = absPath(readLink(path), dirOf(path));
while (true) {
if (lstat(path.c_str(), &st))
throw SysError(format("getting status of `%1%'") % path);
if (!S_ISLNK(st.st_mode)) break;
path = absPath(readLink(path), dirOf(path));
}
/* If `path' refers to a directory, append `/default.nix'. */
if (stat(path.c_str(), &st))
@@ -381,20 +484,8 @@ Expr parseExprFromFile(EvalState & state, Path path)
if (S_ISDIR(st.st_mode))
path = canonPath(path + "/default.nix");
/* Read the input file. We can't use SGparseFile() because it's
broken, so we read the input ourselves and call
SGparseString(). */
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
if (fd == -1) throw SysError(format("opening `%1%'") % path);
if (fstat(fd, &st) == -1)
throw SysError(format("statting `%1%'") % path);
char text[st.st_size + 1];
readFull(fd, (unsigned char *) text, st.st_size);
text[st.st_size] = 0;
return parse(state, text, path, dirOf(path));
/* Read and parse the input file. */
return parse(state, readFile(path).c_str(), path, dirOf(path));
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,17 @@
pkglib_LTLIBRARIES = libext3cow.la
libext3cow_la_SOURCES = epoch2date.c snapshot.cc tt.c ext3cow_tools.h ext3cow_fs.h
pkginclude_HEADERS = snapshot.hh
#TODO linux kernel header
libext3cow_la_LIBADD = ../libutil/libutil.la \
../boost/format/libformat.la
AM_CXXFLAGS = -Wall \
-I$(srcdir)/.. ${aterm_include} \
-I$(srcdir)/../libutil
AM_CFLAGS = \
${aterm_include}

Some files were not shown because too many files have changed in this diff Show More