Initial commit published for NUR
authorIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 13 Dec 2018 20:25:24 +0000 (21:25 +0100)
committerIsmaël Bouya <ismael.bouya@normalesup.org>
Thu, 23 May 2019 23:40:13 +0000 (01:40 +0200)
352 files changed:
.gitignore [new file with mode: 0644]
LICENSE [new file with mode: 0644]
default.nix [new file with mode: 0644]
fetch_version [new file with mode: 0755]
lib/node-env.nix [new file with mode: 0644]
libs.nix [new file with mode: 0644]
modules/default.nix [new file with mode: 0644]
modules/myids.nix [new file with mode: 0644]
modules/secrets.nix [new file with mode: 0644]
modules/webapps/diaspora.nix [new file with mode: 0644]
modules/webapps/etherpad-lite.nix [new file with mode: 0644]
modules/webapps/mastodon.nix [new file with mode: 0644]
modules/webapps/mediagoblin.nix [new file with mode: 0644]
modules/webapps/peertube.nix [new file with mode: 0644]
modules/webapps/webstats/default.nix [new file with mode: 0644]
modules/webapps/webstats/goaccess.conf [new file with mode: 0644]
modules/websites/default.nix [new file with mode: 0644]
modules/websites/httpd-service-builder.nix [new file with mode: 0644]
modules/websites/nosslVhost/index.html [new file with mode: 0644]
nix_path_env [new file with mode: 0644]
overlays/bitlbee/bitlbee_long_nicks.patch [new file with mode: 0644]
overlays/bitlbee/default.nix [new file with mode: 0644]
overlays/bundix/default.nix [new file with mode: 0644]
overlays/databases/mysql/default.nix [new file with mode: 0644]
overlays/databases/postgresql/default.nix [new file with mode: 0644]
overlays/databases/postgresql/postgresql_run_socket_path.patch [new file with mode: 0644]
overlays/default.nix [new file with mode: 0644]
overlays/dwm/default.nix [new file with mode: 0644]
overlays/dwm/dwm_config.h [new file with mode: 0644]
overlays/elinks/default.nix [new file with mode: 0644]
overlays/elinks/elinks.json [new file with mode: 0644]
overlays/environments/default.nix [new file with mode: 0644]
overlays/environments/immae-eu.nix [new file with mode: 0644]
overlays/gitweb/default.nix [new file with mode: 0644]
overlays/gitweb/theme/git-favicon.png [new file with mode: 0644]
overlays/gitweb/theme/git-logo.png [new file with mode: 0644]
overlays/gitweb/theme/gitweb.css [new file with mode: 0644]
overlays/gitweb/theme/gitweb.js [new file with mode: 0644]
overlays/goaccess/default.nix [new file with mode: 0644]
overlays/kanboard/default.nix [new file with mode: 0644]
overlays/ldapvi/default.nix [new file with mode: 0644]
overlays/ldapvi/ldapvi.json [new file with mode: 0644]
overlays/lesspipe/default.nix [new file with mode: 0644]
overlays/neomutt/default.nix [new file with mode: 0644]
overlays/nixops/default.nix [new file with mode: 0644]
overlays/pass/default.nix [new file with mode: 0644]
overlays/pass/pass-fix-pass-init.patch [new file with mode: 0644]
overlays/pass/pass.json [new file with mode: 0644]
overlays/pelican/default.nix [new file with mode: 0644]
overlays/pelican/pelican.json [new file with mode: 0644]
overlays/profanity/default.nix [new file with mode: 0644]
overlays/python-packages/buildbot.nix [new file with mode: 0644]
overlays/python-packages/default.nix [new file with mode: 0644]
overlays/sc-im/default.nix [new file with mode: 0644]
overlays/shaarli/default.nix [new file with mode: 0644]
overlays/shaarli/shaarli_ldap.patch [new file with mode: 0644]
overlays/slrn/default.nix [new file with mode: 0644]
overlays/taskwarrior/default.nix [new file with mode: 0644]
overlays/vit/default.nix [new file with mode: 0644]
overlays/vit/vit.json [new file with mode: 0644]
overlays/weboob/default.nix [new file with mode: 0644]
overlays/weechat/default.nix [new file with mode: 0644]
overlays/ympd/default.nix [new file with mode: 0644]
overlays/ympd/ympd-password-env.patch [new file with mode: 0644]
overlays/ympd/ympd.json [new file with mode: 0644]
pkgs/bitlbee-mastodon/default.nix [new file with mode: 0644]
pkgs/boinctui/default.nix [new file with mode: 0644]
pkgs/cnagios/cnagios.json [new file with mode: 0644]
pkgs/cnagios/default.nix [new file with mode: 0644]
pkgs/composer-env/default.nix [new file with mode: 0644]
pkgs/crypto/cardano/daedalus.json [new file with mode: 0644]
pkgs/crypto/cardano/default.nix [new file with mode: 0644]
pkgs/crypto/iota-cli-app/default.nix [new file with mode: 0644]
pkgs/crypto/iota-cli-app/iota-cli-app.json [new file with mode: 0644]
pkgs/crypto/iota-cli-app/node-packages.nix [new file with mode: 0644]
pkgs/crypto/sia/default.nix [new file with mode: 0644]
pkgs/default.nix [new file with mode: 0644]
pkgs/duply/default.nix [new file with mode: 0644]
pkgs/flrn/default.nix [new file with mode: 0644]
pkgs/flrn/flrn.json [new file with mode: 0644]
pkgs/genius/default.nix [new file with mode: 0644]
pkgs/mpd_0_21/default.nix [new file with mode: 0644]
pkgs/mtop/default.nix [new file with mode: 0644]
pkgs/mutt-ics/default.nix [new file with mode: 0644]
pkgs/mutt-ics/mutt-ics.json [new file with mode: 0644]
pkgs/muttprint/0.73-4.diff.gz [new file with mode: 0644]
pkgs/muttprint/default.nix [new file with mode: 0644]
pkgs/muttprint/regex.patch [new file with mode: 0644]
pkgs/muttprint/two_edge.patch [new file with mode: 0644]
pkgs/nagios-cli/default.nix [new file with mode: 0644]
pkgs/nagios-cli/nagios-cli.json [new file with mode: 0644]
pkgs/nagnu/default.nix [new file with mode: 0644]
pkgs/nagnu/nagnu.json [new file with mode: 0644]
pkgs/note/default.nix [new file with mode: 0644]
pkgs/notmuch/notmuch-python/default.nix [new file with mode: 0644]
pkgs/notmuch/notmuch-vim/default.nix [new file with mode: 0644]
pkgs/pg_activity/default.nix [new file with mode: 0644]
pkgs/pg_activity/pg_activity.json [new file with mode: 0644]
pkgs/pgloader/default.nix [new file with mode: 0644]
pkgs/pgloader/pgloader.json [new file with mode: 0644]
pkgs/pure-ftpd/default.nix [new file with mode: 0644]
pkgs/python-packages/apprise/apprise.json [new file with mode: 0644]
pkgs/python-packages/apprise/default.nix [new file with mode: 0644]
pkgs/python-packages/buildbot/plugins/buildslist/bower.nix [new file with mode: 0644]
pkgs/python-packages/buildbot/plugins/buildslist/buildslist.json [new file with mode: 0644]
pkgs/python-packages/buildbot/plugins/buildslist/default.nix [new file with mode: 0644]
pkgs/python-packages/buildbot/plugins/buildslist/yarn-packages.nix [new file with mode: 0644]
pkgs/python-packages/buildbot/plugins/default.nix [new file with mode: 0644]
pkgs/python-packages/default.nix [new file with mode: 0644]
pkgs/python-packages/wokkel.nix [new file with mode: 0644]
pkgs/slang_1/default.nix [new file with mode: 0644]
pkgs/telegram-cli/default.nix [new file with mode: 0644]
pkgs/telegram-cli/telegram-cli.json [new file with mode: 0644]
pkgs/telegram-cli/telegram-cli.patch [new file with mode: 0644]
pkgs/telegram-history-dump/default.nix [new file with mode: 0644]
pkgs/telegram-history-dump/telegram-history-dump.json [new file with mode: 0644]
pkgs/telegramircd/default.nix [new file with mode: 0644]
pkgs/telegramircd/telegramircd.json [new file with mode: 0644]
pkgs/telethon_sync/default.nix [new file with mode: 0644]
pkgs/terminal-velocity/default.nix [new file with mode: 0644]
pkgs/terminal-velocity/fix_build.patch [new file with mode: 0644]
pkgs/terminal-velocity/python3_support.patch [new file with mode: 0644]
pkgs/terminal-velocity/sort_found_notes.patch [new file with mode: 0644]
pkgs/tiv/default.nix [new file with mode: 0644]
pkgs/tiv/tiv_builder.sh [new file with mode: 0644]
pkgs/unicode/default.nix [new file with mode: 0644]
pkgs/webapps/adminer/default.nix [new file with mode: 0644]
pkgs/webapps/apache-theme/default.nix [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/.htaccess [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/footer.html [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/header.html [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/archive.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/audio.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/authors.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/bin.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/blank.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/bmp.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/c.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/calc.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/cd.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/copying.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/cpp.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/css.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/deb.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/default.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/diff.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/doc.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/draw.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/eps.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/exe.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder-home.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder-open.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder-page.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder-parent-old.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder-parent.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/folder.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/gif.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/gzip.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/h.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/hpp.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/html.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/ico.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/image.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/install.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/java.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/jpg.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/js.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/json.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/log.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/makefile.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/markdown.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/package.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/pdf.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/php.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/playlist.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/png.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/pres.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/ps.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/psd.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/py.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/rar.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/rb.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/readme.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/rpm.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/rss.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/rtf.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/script.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/source.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/sql.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/tar.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/tex.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/text.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/tiff.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/unknown.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/vcal.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/video.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/xml.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/icons/zip.png [new file with mode: 0644]
pkgs/webapps/apache-theme/theme/style.css [new file with mode: 0644]
pkgs/webapps/awl/default.nix [new file with mode: 0644]
pkgs/webapps/davical/davical_19eb79ebf9250e5f339675319902458c40ed1755.patch [new file with mode: 0644]
pkgs/webapps/davical/default.nix [new file with mode: 0644]
pkgs/webapps/default.nix [new file with mode: 0644]
pkgs/webapps/diaspora/default.nix [new file with mode: 0644]
pkgs/webapps/diaspora/diaspora.json [new file with mode: 0644]
pkgs/webapps/diaspora/gemset.nix [new file with mode: 0644]
pkgs/webapps/diaspora/gemset_ldap.nix [new file with mode: 0644]
pkgs/webapps/diaspora/ldap.patch [new file with mode: 0644]
pkgs/webapps/dokuwiki/default.nix [new file with mode: 0644]
pkgs/webapps/dokuwiki/dokuwiki.json [new file with mode: 0644]
pkgs/webapps/dokuwiki/plugins/farmer.nix [new file with mode: 0644]
pkgs/webapps/dokuwiki/plugins/todo.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/default.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/etherpad-lite.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/libreoffice_patch.diff [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_aa_file_menu_toolbar/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_aa_file_menu_toolbar/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_adminpads/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_adminpads/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_align/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_align/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_bookmark/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_bookmark/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_clear_formatting/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_clear_formatting/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_colors/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_colors/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_copy_paste_select_all/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_copy_paste_select_all/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_cursortrace/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_cursortrace/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_embedmedia/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_embedmedia/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_font_family/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_font_family/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_font_size/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_font_size/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_headings2/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_headings2/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_ldapauth/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_ldapauth/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_line_height/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_line_height/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_markdown/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_markdown/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_previewimages/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_previewimages/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_ruler/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_ruler/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_scrollto/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_scrollto/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_set_title_on_pad/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_set_title_on_pad/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_subscript_and_superscript/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_subscript_and_superscript/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_timesliderdiff/node-packages.json [new file with mode: 0644]
pkgs/webapps/etherpad-lite/modules/ep_timesliderdiff/node-packages.nix [new file with mode: 0644]
pkgs/webapps/etherpad-lite/node-packages.nix [new file with mode: 0644]
pkgs/webapps/infcloud/default.nix [new file with mode: 0644]
pkgs/webapps/infcloud/infcloud_config.js [new file with mode: 0644]
pkgs/webapps/mantisbt_2/bug_report.php.diff [new file with mode: 0644]
pkgs/webapps/mantisbt_2/bug_report_page.php.diff [new file with mode: 0644]
pkgs/webapps/mantisbt_2/bugnote_add.php.diff [new file with mode: 0644]
pkgs/webapps/mantisbt_2/bugnote_add_inc.php.diff [new file with mode: 0644]
pkgs/webapps/mantisbt_2/default.nix [new file with mode: 0644]
pkgs/webapps/mantisbt_2/plugins/slack/default.nix [new file with mode: 0644]
pkgs/webapps/mantisbt_2/plugins/source-integration/Source.API.php.diff [new file with mode: 0644]
pkgs/webapps/mantisbt_2/plugins/source-integration/default.nix [new file with mode: 0644]
pkgs/webapps/mastodon/default.nix [new file with mode: 0644]
pkgs/webapps/mastodon/gemset.nix [new file with mode: 0644]
pkgs/webapps/mastodon/mastodon.json [new file with mode: 0644]
pkgs/webapps/mastodon/yarn-packages.nix [new file with mode: 0644]
pkgs/webapps/mediagoblin/bower-packages.nix [new file with mode: 0644]
pkgs/webapps/mediagoblin/default.nix [new file with mode: 0644]
pkgs/webapps/mediagoblin/ldap_fix.py [new file with mode: 0644]
pkgs/webapps/mediagoblin/mediagoblin.json [new file with mode: 0644]
pkgs/webapps/mediagoblin/plugins/basicsearch/default.nix [new file with mode: 0644]
pkgs/webapps/mediagoblin/tempita.json [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/audioplayer.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/bookmarks.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/calendar.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/carnet.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/contacts.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/deck.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/files_markdown.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/flowupload.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/gpxedit.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/gpxpod.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/keeweb.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/music.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/notes.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/ocsms.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/passman.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/spreed.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/apps/tasks.nix [new file with mode: 0644]
pkgs/webapps/nextcloud/default.nix [new file with mode: 0644]
pkgs/webapps/peertube/default.nix [new file with mode: 0644]
pkgs/webapps/peertube/ldap.patch [new file with mode: 0644]
pkgs/webapps/peertube/ldap_yarn.patch [new file with mode: 0644]
pkgs/webapps/peertube/peertube.json [new file with mode: 0644]
pkgs/webapps/peertube/sendmail.patch [new file with mode: 0644]
pkgs/webapps/peertube/yarn-packages.nix [new file with mode: 0644]
pkgs/webapps/peertube/yarn_fix_bluebird.patch [new file with mode: 0644]
pkgs/webapps/peertube/yarn_fix_bluebird_ldap.patch [new file with mode: 0644]
pkgs/webapps/phpldapadmin/default.nix [new file with mode: 0644]
pkgs/webapps/phpldapadmin/ldap-align-button.patch [new file with mode: 0644]
pkgs/webapps/phpldapadmin/ldap-disable-mcrypt.patch [new file with mode: 0644]
pkgs/webapps/phpldapadmin/ldap-php5_5.patch [new file with mode: 0644]
pkgs/webapps/phpldapadmin/ldap-php7_2.patch [new file with mode: 0644]
pkgs/webapps/phpldapadmin/ldap-sort-in-templates.patch [new file with mode: 0644]
pkgs/webapps/rompr/default.nix [new file with mode: 0644]
pkgs/webapps/rompr/rompr.json [new file with mode: 0644]
pkgs/webapps/roundcubemail/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/automatic_addressbook/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/carddav/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/contextmenu/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/contextmenu_folder/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/html5_notifier/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/ident_switch/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/message_highlight/default.nix [new file with mode: 0644]
pkgs/webapps/roundcubemail/plugins/thunderbird_labels/default.nix [new file with mode: 0644]
pkgs/webapps/spip/default.nix [new file with mode: 0644]
pkgs/webapps/spip/spip_ldap_patch.patch [new file with mode: 0644]
pkgs/webapps/spip/spip_mes_options.php [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/Gemfile.lock [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/default.nix [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/fixes.patch [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/gemset.nix [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/taskwarrior-web.json [new file with mode: 0644]
pkgs/webapps/taskwarrior-web/thin.patch [new file with mode: 0644]
pkgs/webapps/ttrss/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/af_feedmod/af_feedmod.json [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/af_feedmod/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/af_feedmod/type_replace.patch [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/auth_ldap/auth-ldap.json [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/auth_ldap/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/feediron/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/feediron/feediron.json [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/feediron/json_reformat.patch [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/ff_instagram/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/ff_instagram/ff_instagram.json [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/tumblr_gdpr_ua/default.nix [new file with mode: 0644]
pkgs/webapps/ttrss/plugins/tumblr_gdpr_ua/tumblr_gdpr_ua.json [new file with mode: 0644]
pkgs/webapps/ttrss/tt-rss.json [new file with mode: 0644]
pkgs/webapps/wallabag/default.nix [new file with mode: 0644]
pkgs/webapps/wallabag/ldap.patch [new file with mode: 0644]
pkgs/webapps/yourls/default.nix [new file with mode: 0644]
pkgs/webapps/yourls/plugins/ldap/default.nix [new file with mode: 0644]
pkgs/webapps/yourls/plugins/ldap/ldap.json [new file with mode: 0644]
pkgs/webapps/yourls/yourls.json [new file with mode: 0644]
scripts/make-env [new file with mode: 0755]
scripts/nix_infos [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..feb036e
--- /dev/null
@@ -0,0 +1,2 @@
+/result*
+/versions_log
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..243190c
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,24 @@
+The MIT License (MIT)
+
+Copyright (c) 2011-2019 Ismaël Bouya http://www.normalesup.org/~bouya/
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+
+Feel like tipping/donating? https://www.immae.eu/licenses_and_tipping
diff --git a/default.nix b/default.nix
new file mode 100644 (file)
index 0000000..c7f515b
--- /dev/null
@@ -0,0 +1,11 @@
+{ pkgs ? import <nixpkgs> {} }:
+let
+  pkgs_ = pkgs;
+  mypkgs = import ./pkgs { pkgs = pkgs_; };
+in
+{
+  lib = import ./libs.nix { pkgs = pkgs_; };
+  modules = import ./modules;
+  overlays = import ./overlays;
+  pkgs = mypkgs;
+} // mypkgs
diff --git a/fetch_version b/fetch_version
new file mode 100755 (executable)
index 0000000..a0325f6
--- /dev/null
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+usage() {
+  echo "$0 file.json"
+  echo "$0 [-n|--name name] [-b|--branch branch_or_rev] [-f|--file out_file] [-h|--help] (-u|--url) url"
+  exit
+}
+
+branch="master"
+while [[ $# -gt 0 ]]; do
+  a="$1"
+  shift
+  case "$a" in
+    *.json)
+      file=$a
+      content=$(cat $a)
+      name="$(echo "$content" | jq -r ".meta.name")"
+      url="$(echo "$content" | jq -r ".meta.url")"
+      branch="$(echo "$content" | jq -r ".meta.branch")"
+      ;;
+    -n|--name)
+      name=$1
+      shift
+      ;;
+    -u|--url)
+      url=$1
+      shift
+      ;;
+    -b|--branch)
+      branch=$1
+      shift
+      ;;
+    -f|--file)
+      file=$1
+      shift
+      ;;
+    -h|--help)
+      usage
+      ;;
+  esac
+done
+if [ -z "$url" ]; then
+  usage
+fi
+if [ -z "$name" ]; then
+  name=$(echo "$url" | cut -d"/" -f5)
+fi
+if [ -z "$file" ]; then
+  file=$name.json
+fi
+
+# function fetch_ledger () {
+#   pushd $HOME/projets/ledger >/dev/null 2>/dev/null
+#   git fetch origin
+#   tag="$(git describe origin/next | sed -e "s/^v//")"
+#   rev="$(git show-ref -s refs/remotes/origin/next)"
+#   sha="$(nix-prefetch-url --unpack file://<(git archive --format=tar.gz HEAD) 2>/dev/null)"
+#   popd >/dev/null 2>/dev/null
+# }
+
+# awk_describe='BEGIN {
+#   FS = "[ /^]+"
+#   while ("git ls-remote " ARGV[1] "| sort -Vk2" | getline) {
+#     if (!sha)
+#       sha = substr($0, 1, 7)
+#     tag = $3
+#   }
+#   while ("curl -s " ARGV[1] "/releases/tag/" tag | getline)
+#     if ($3 ~ "commits")
+#       com = $2
+#   printf com ? "%s-%s-g%s\n" : "%s\n", tag, com, sha
+# }'
+
+function get_ref () {
+  case "$1" in
+    refs/*)
+      echo "$1"
+      ;;
+    *)
+      echo "refs/heads/$1"
+      ;;
+  esac
+}
+
+function get_name () {
+  branch="$1"
+  rev="$2"
+  minirev=${rev:0:7}
+
+  case "$branch" in
+    refs/tags/*)
+      b="${branch#refs/tags/}"
+      echo "${b//\//-}"
+      ;;
+    refs/heads/*)
+      b=${branch#refs/heads/}
+      echo "$minirev-${b//\//-}"
+      ;;
+    refs/*)
+      b=${branch#refs/}
+      echo "$minirev-${b//\//-}"
+      ;;
+    *)
+      echo "$minirev-${branch//\//-}"
+      ;;
+  esac
+}
+
+function fetch_github () {
+  rev="$(git ls-remote --refs $url $(get_ref $branch) | head -n1 | cut -f1)"
+  sha="$(nix-prefetch-url --unpack $url/archive/$rev.tar.gz)"
+  # Différent du git-describe et github-spécifique
+  #tag=$(echo "$awk_describe" | awk -f - $url | sed -e "s/^v//")
+  tag=$(get_name $branch $rev)
+}
+
+function fetch_other () {
+  rev="$(git ls-remote --refs $url $(get_ref $branch) | head -n1 | cut -f1)"
+  sha="$(nix-prefetch-git --url $url --rev $(get_ref $branch) | jq -r '.sha256')"
+  tag=$(get_name $branch $rev)
+}
+
+case "$url" in
+  https://*github.com/*)
+    fetch_github 2>/dev/null
+    owner=$(echo "$url" | cut -d"/" -f4)
+    repo=$(echo "$url" | cut -d"/" -f5)
+
+    F='{
+      "tag": $tag,
+      "meta": {
+        "name": $name,
+        "url": $url,
+        "branch": $branch
+      },
+      "github": {
+        "owner": $owner,
+        "repo": $repo,
+        "rev": $rev,
+        "sha256": $sha,
+        "fetchSubmodules": true
+      }
+    }'
+    ;;
+  *)
+    fetch_other 2>/dev/null
+    F='{
+      "tag": $tag,
+      "meta": {
+        "name": $name,
+        "url": $url,
+        "branch": $branch
+      },
+      "git": {
+        "url": $url,
+        "rev": $rev,
+        "sha256": $sha,
+        "fetchSubmodules": true
+      }
+    }'
+    ;;
+esac
+
+jq -n \
+  --arg name "$name" \
+  --arg owner "$owner" \
+  --arg repo "$repo" \
+  --arg tag "$tag" \
+  --arg rev "$rev" \
+  --arg url "$url" \
+  --arg branch "$branch" \
+  --arg sha "$sha" \
+  "$F" > $file
diff --git a/lib/node-env.nix b/lib/node-env.nix
new file mode 100644 (file)
index 0000000..720e0cc
--- /dev/null
@@ -0,0 +1,542 @@
+# This file originates from node2nix
+
+{stdenv, nodejs, python2, utillinux, libtool, runCommand, writeTextFile}:
+
+let
+  python = if nodejs ? python then nodejs.python else python2;
+
+  # Create a tar wrapper that filters all the 'Ignoring unknown extended header keyword' noise
+  tarWrapper = runCommand "tarWrapper" {} ''
+    mkdir -p $out/bin
+
+    cat > $out/bin/tar <<EOF
+    #! ${stdenv.shell} -e
+    $(type -p tar) "\$@" --warning=no-unknown-keyword
+    EOF
+
+    chmod +x $out/bin/tar
+  '';
+
+  # Function that generates a TGZ file from a NPM project
+  buildNodeSourceDist =
+    { name, version, src, ... }:
+
+    stdenv.mkDerivation {
+      name = "node-tarball-${name}-${version}";
+      inherit src;
+      buildInputs = [ nodejs ];
+      buildPhase = ''
+        export HOME=$TMPDIR
+        tgzFile=$(npm pack | tail -n 1) # Hooks to the pack command will add output (https://docs.npmjs.com/misc/scripts)
+      '';
+      installPhase = ''
+        mkdir -p $out/tarballs
+        mv $tgzFile $out/tarballs
+        mkdir -p $out/nix-support
+        echo "file source-dist $out/tarballs/$tgzFile" >> $out/nix-support/hydra-build-products
+      '';
+    };
+
+  includeDependencies = {dependencies}:
+    stdenv.lib.optionalString (dependencies != [])
+      (stdenv.lib.concatMapStrings (dependency:
+        ''
+          # Bundle the dependencies of the package
+          mkdir -p node_modules
+          cd node_modules
+
+          # Only include dependencies if they don't exist. They may also be bundled in the package.
+          if [ ! -e "${dependency.name}" ]
+          then
+              ${composePackage dependency}
+          fi
+
+          cd ..
+        ''
+      ) dependencies);
+
+  # Recursively composes the dependencies of a package
+  composePackage = { name, packageName, src, dependencies ? [], ... }@args:
+    ''
+      DIR=$(pwd)
+      cd $TMPDIR
+
+      unpackFile ${src}
+
+      # Make the base dir in which the target dependency resides first
+      mkdir -p "$(dirname "$DIR/${packageName}")"
+
+      if [ -f "${src}" ]
+      then
+          # Figure out what directory has been unpacked
+          packageDir="$(find . -maxdepth 1 -type d | tail -1)"
+
+          # Restore write permissions to make building work
+          find "$packageDir" -type d -print0 | xargs -0 chmod u+x
+          chmod -R u+w "$packageDir"
+
+          # Move the extracted tarball into the output folder
+          mv "$packageDir" "$DIR/${packageName}"
+      elif [ -d "${src}" ]
+      then
+          # Get a stripped name (without hash) of the source directory.
+          # On old nixpkgs it's already set internally.
+          if [ -z "$strippedName" ]
+          then
+              strippedName="$(stripHash ${src})"
+          fi
+
+          # Restore write permissions to make building work
+          chmod -R u+w "$strippedName"
+
+          # Move the extracted directory into the output folder
+          mv "$strippedName" "$DIR/${packageName}"
+      fi
+
+      # Unset the stripped name to not confuse the next unpack step
+      unset strippedName
+
+      # Include the dependencies of the package
+      cd "$DIR/${packageName}"
+      ${includeDependencies { inherit dependencies; }}
+      cd ..
+      ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+    '';
+
+  pinpointDependencies = {dependencies, production}:
+    let
+      pinpointDependenciesFromPackageJSON = writeTextFile {
+        name = "pinpointDependencies.js";
+        text = ''
+          var fs = require('fs');
+          var path = require('path');
+
+          function resolveDependencyVersion(location, name) {
+              if(location == process.env['NIX_STORE']) {
+                  return null;
+              } else {
+                  var dependencyPackageJSON = path.join(location, "node_modules", name, "package.json");
+
+                  if(fs.existsSync(dependencyPackageJSON)) {
+                      var dependencyPackageObj = JSON.parse(fs.readFileSync(dependencyPackageJSON));
+
+                      if(dependencyPackageObj.name == name) {
+                          return dependencyPackageObj.version;
+                      }
+                  } else {
+                      return resolveDependencyVersion(path.resolve(location, ".."), name);
+                  }
+              }
+          }
+
+          function replaceDependencies(dependencies) {
+              if(typeof dependencies == "object" && dependencies !== null) {
+                  for(var dependency in dependencies) {
+                      var resolvedVersion = resolveDependencyVersion(process.cwd(), dependency);
+
+                      if(resolvedVersion === null) {
+                          process.stderr.write("WARNING: cannot pinpoint dependency: "+dependency+", context: "+process.cwd()+"\n");
+                      } else {
+                          dependencies[dependency] = resolvedVersion;
+                      }
+                  }
+              }
+          }
+
+          /* Read the package.json configuration */
+          var packageObj = JSON.parse(fs.readFileSync('./package.json'));
+
+          /* Pinpoint all dependencies */
+          replaceDependencies(packageObj.dependencies);
+          if(process.argv[2] == "development") {
+              replaceDependencies(packageObj.devDependencies);
+          }
+          replaceDependencies(packageObj.optionalDependencies);
+
+          /* Write the fixed package.json file */
+          fs.writeFileSync("package.json", JSON.stringify(packageObj, null, 2));
+        '';
+      };
+    in
+    ''
+      node ${pinpointDependenciesFromPackageJSON} ${if production then "production" else "development"}
+
+      ${stdenv.lib.optionalString (dependencies != [])
+        ''
+          if [ -d node_modules ]
+          then
+              cd node_modules
+              ${stdenv.lib.concatMapStrings (dependency: pinpointDependenciesOfPackage dependency) dependencies}
+              cd ..
+          fi
+        ''}
+    '';
+
+  # Recursively traverses all dependencies of a package and pinpoints all
+  # dependencies in the package.json file to the versions that are actually
+  # being used.
+
+  pinpointDependenciesOfPackage = { packageName, dependencies ? [], production ? true, ... }@args:
+    ''
+      if [ -d "${packageName}" ]
+      then
+          cd "${packageName}"
+          ${pinpointDependencies { inherit dependencies production; }}
+          cd ..
+          ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+      fi
+    '';
+
+  # Extract the Node.js source code which is used to compile packages with
+  # native bindings
+  nodeSources = runCommand "node-sources" {} ''
+    tar --no-same-owner --no-same-permissions -xf ${nodejs.src}
+    mv node-* $out
+  '';
+
+  # Script that adds _integrity fields to all package.json files to prevent NPM from consulting the cache (that is empty)
+  addIntegrityFieldsScript = writeTextFile {
+    name = "addintegrityfields.js";
+    text = ''
+      var fs = require('fs');
+      var path = require('path');
+
+      function augmentDependencies(baseDir, dependencies) {
+          for(var dependencyName in dependencies) {
+              var dependency = dependencies[dependencyName];
+
+              // Open package.json and augment metadata fields
+              var packageJSONDir = path.join(baseDir, "node_modules", dependencyName);
+              var packageJSONPath = path.join(packageJSONDir, "package.json");
+
+              if(fs.existsSync(packageJSONPath)) { // Only augment packages that exist. Sometimes we may have production installs in which development dependencies can be ignored
+                  console.log("Adding metadata fields to: "+packageJSONPath);
+                  var packageObj = JSON.parse(fs.readFileSync(packageJSONPath));
+
+                  if(dependency.integrity) {
+                      packageObj["_integrity"] = dependency.integrity;
+                  } else {
+                      packageObj["_integrity"] = "sha1-000000000000000000000000000="; // When no _integrity string has been provided (e.g. by Git dependencies), add a dummy one. It does not seem to harm and it bypasses downloads.
+                  }
+
+                  packageObj["_resolved"] = dependency.version; // Set the resolved version to the version identifier. This prevents NPM from cloning Git repositories.
+                  fs.writeFileSync(packageJSONPath, JSON.stringify(packageObj, null, 2));
+              }
+
+              // Augment transitive dependencies
+              if(dependency.dependencies !== undefined) {
+                  augmentDependencies(packageJSONDir, dependency.dependencies);
+              }
+          }
+      }
+
+      if(fs.existsSync("./package-lock.json")) {
+          var packageLock = JSON.parse(fs.readFileSync("./package-lock.json"));
+
+          if(packageLock.lockfileVersion !== 1) {
+             process.stderr.write("Sorry, I only understand lock file version 1!\n");
+             process.exit(1);
+          }
+
+          if(packageLock.dependencies !== undefined) {
+              augmentDependencies(".", packageLock.dependencies);
+          }
+      }
+    '';
+  };
+
+  # Reconstructs a package-lock file from the node_modules/ folder structure and package.json files with dummy sha1 hashes
+  reconstructPackageLock = writeTextFile {
+    name = "addintegrityfields.js";
+    text = ''
+      var fs = require('fs');
+      var path = require('path');
+
+      var packageObj = JSON.parse(fs.readFileSync("package.json"));
+
+      var lockObj = {
+          name: packageObj.name,
+          version: packageObj.version,
+          lockfileVersion: 1,
+          requires: true,
+          dependencies: {}
+      };
+
+      function augmentPackageJSON(filePath, dependencies) {
+          var packageJSON = path.join(filePath, "package.json");
+          if(fs.existsSync(packageJSON)) {
+              var packageObj = JSON.parse(fs.readFileSync(packageJSON));
+              dependencies[packageObj.name] = {
+                  version: packageObj.version,
+                  integrity: "sha1-000000000000000000000000000=",
+                  dependencies: {}
+              };
+              processDependencies(path.join(filePath, "node_modules"), dependencies[packageObj.name].dependencies);
+          }
+      }
+
+      function processDependencies(dir, dependencies) {
+          if(fs.existsSync(dir)) {
+              var files = fs.readdirSync(dir);
+
+              files.forEach(function(entry) {
+                  var filePath = path.join(dir, entry);
+                  var stats = fs.statSync(filePath);
+
+                  if(stats.isDirectory()) {
+                      if(entry.substr(0, 1) == "@") {
+                          // When we encounter a namespace folder, augment all packages belonging to the scope
+                          var pkgFiles = fs.readdirSync(filePath);
+
+                          pkgFiles.forEach(function(entry) {
+                              if(stats.isDirectory()) {
+                                  var pkgFilePath = path.join(filePath, entry);
+                                  augmentPackageJSON(pkgFilePath, dependencies);
+                              }
+                          });
+                      } else {
+                          augmentPackageJSON(filePath, dependencies);
+                      }
+                  }
+              });
+          }
+      }
+
+      processDependencies("node_modules", lockObj.dependencies);
+
+      fs.writeFileSync("package-lock.json", JSON.stringify(lockObj, null, 2));
+    '';
+  };
+
+  # Builds and composes an NPM package including all its dependencies
+  buildNodePackage =
+    { name
+    , packageName
+    , version
+    , dependencies ? []
+    , buildInputs ? []
+    , production ? true
+    , npmFlags ? ""
+    , dontNpmInstall ? false
+    , bypassCache ? false
+    , preRebuild ? ""
+    , dontStrip ? true
+    , unpackPhase ? "true"
+    , buildPhase ? "true"
+    , ... }@args:
+
+    let
+      forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
+      extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" "dontStrip" "dontNpmInstall" "preRebuild" "unpackPhase" "buildPhase" ];
+    in
+    stdenv.mkDerivation ({
+      name = "node-${name}-${version}";
+      buildInputs = [ tarWrapper python nodejs ]
+        ++ stdenv.lib.optional (stdenv.isLinux) utillinux
+        ++ stdenv.lib.optional (stdenv.isDarwin) libtool
+        ++ buildInputs;
+
+      inherit dontStrip; # Stripping may fail a build for some package deployments
+      inherit dontNpmInstall preRebuild unpackPhase buildPhase;
+
+      compositionScript = composePackage args;
+      pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+      passAsFile = [ "compositionScript" "pinpointDependenciesScript" ];
+
+      installPhase = ''
+        # Create and enter a root node_modules/ folder
+        mkdir -p $out/lib/node_modules
+        cd $out/lib/node_modules
+
+        # Compose the package and all its dependencies
+        source $compositionScriptPath
+
+        # Pinpoint the versions of all dependencies to the ones that are actually being used
+        echo "pinpointing versions of dependencies..."
+        source $pinpointDependenciesScriptPath
+
+        # Patch the shebangs of the bundled modules to prevent them from
+        # calling executables outside the Nix store as much as possible
+        patchShebangs .
+
+        # Deploy the Node.js package by running npm install. Since the
+        # dependencies have been provided already by ourselves, it should not
+        # attempt to install them again, which is good, because we want to make
+        # it Nix's responsibility. If it needs to install any dependencies
+        # anyway (e.g. because the dependency parameters are
+        # incomplete/incorrect), it fails.
+        #
+        # The other responsibilities of NPM are kept -- version checks, build
+        # steps, postprocessing etc.
+
+        export HOME=$TMPDIR
+        cd "${packageName}"
+        runHook preRebuild
+
+        ${stdenv.lib.optionalString bypassCache ''
+          if [ ! -f package-lock.json ]
+          then
+              echo "No package-lock.json file found, reconstructing..."
+              node ${reconstructPackageLock}
+          fi
+
+          node ${addIntegrityFieldsScript}
+        ''}
+
+        npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
+
+        if [ "$dontNpmInstall" != "1" ]
+        then
+            # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
+            rm -f npm-shrinkwrap.json
+
+            npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
+        fi
+
+        # Create symlink to the deployed executable folder, if applicable
+        if [ -d "$out/lib/node_modules/.bin" ]
+        then
+            ln -s $out/lib/node_modules/.bin $out/bin
+        fi
+
+        # Create symlinks to the deployed manual page folders, if applicable
+        if [ -d "$out/lib/node_modules/${packageName}/man" ]
+        then
+            mkdir -p $out/share
+            for dir in "$out/lib/node_modules/${packageName}/man/"*
+            do
+                mkdir -p $out/share/man/$(basename "$dir")
+                for page in "$dir"/*
+                do
+                    ln -s $page $out/share/man/$(basename "$dir")
+                done
+            done
+        fi
+
+        # Run post install hook, if provided
+        runHook postInstall
+      '';
+    } // extraArgs);
+
+  # Builds a development shell
+  buildNodeShell =
+    { name
+    , packageName
+    , version
+    , src
+    , dependencies ? []
+    , buildInputs ? []
+    , production ? true
+    , npmFlags ? ""
+    , dontNpmInstall ? false
+    , bypassCache ? false
+    , dontStrip ? true
+    , unpackPhase ? "true"
+    , buildPhase ? "true"
+    , ... }@args:
+
+    let
+      forceOfflineFlag = if bypassCache then "--offline" else "--registry http://www.example.com";
+
+      extraArgs = removeAttrs args [ "name" "dependencies" "buildInputs" ];
+
+      nodeDependencies = stdenv.mkDerivation ({
+        name = "node-dependencies-${name}-${version}";
+
+        buildInputs = [ tarWrapper python nodejs ]
+          ++ stdenv.lib.optional (stdenv.isLinux) utillinux
+          ++ stdenv.lib.optional (stdenv.isDarwin) libtool
+          ++ buildInputs;
+
+        inherit dontStrip; # Stripping may fail a build for some package deployments
+        inherit dontNpmInstall unpackPhase buildPhase;
+
+        includeScript = includeDependencies { inherit dependencies; };
+        pinpointDependenciesScript = pinpointDependenciesOfPackage args;
+
+        passAsFile = [ "includeScript" "pinpointDependenciesScript" ];
+
+        installPhase = ''
+          mkdir -p $out/${packageName}
+          cd $out/${packageName}
+
+          source $includeScriptPath
+
+          # Create fake package.json to make the npm commands work properly
+          cp ${src}/package.json .
+          chmod 644 package.json
+          ${stdenv.lib.optionalString bypassCache ''
+            if [ -f ${src}/package-lock.json ]
+            then
+                cp ${src}/package-lock.json .
+            fi
+          ''}
+
+          # Pinpoint the versions of all dependencies to the ones that are actually being used
+          echo "pinpointing versions of dependencies..."
+          cd ..
+          ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+          source $pinpointDependenciesScriptPath
+          cd ${packageName}
+
+          # Patch the shebangs of the bundled modules to prevent them from
+          # calling executables outside the Nix store as much as possible
+          patchShebangs .
+
+          export HOME=$PWD
+
+          ${stdenv.lib.optionalString bypassCache ''
+            if [ ! -f package-lock.json ]
+            then
+                echo "No package-lock.json file found, reconstructing..."
+                node ${reconstructPackageLock}
+            fi
+
+            node ${addIntegrityFieldsScript}
+          ''}
+
+          npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} rebuild
+
+          ${stdenv.lib.optionalString (!dontNpmInstall) ''
+            # NPM tries to download packages even when they already exist if npm-shrinkwrap is used.
+            rm -f npm-shrinkwrap.json
+
+            npm ${forceOfflineFlag} --nodedir=${nodeSources} ${npmFlags} ${stdenv.lib.optionalString production "--production"} install
+          ''}
+
+          cd ..
+          ${stdenv.lib.optionalString (builtins.substring 0 1 packageName == "@") "cd .."}
+
+          mv ${packageName} lib
+          ln -s $out/lib/node_modules/.bin $out/bin
+        '';
+      } // extraArgs);
+    in
+    stdenv.mkDerivation {
+      name = "node-shell-${name}-${version}";
+
+      buildInputs = [ python nodejs ] ++ stdenv.lib.optional (stdenv.isLinux) utillinux ++ buildInputs;
+      buildCommand = ''
+        mkdir -p $out/bin
+        cat > $out/bin/shell <<EOF
+        #! ${stdenv.shell} -e
+        $shellHook
+        exec ${stdenv.shell}
+        EOF
+        chmod +x $out/bin/shell
+      '';
+
+      # Provide the dependencies in a development shell through the NODE_PATH environment variable
+      inherit nodeDependencies;
+      shellHook = stdenv.lib.optionalString (dependencies != []) ''
+        export NODE_PATH=$nodeDependencies/lib/node_modules
+      '';
+    };
+in
+{
+  buildNodeSourceDist = stdenv.lib.makeOverridable buildNodeSourceDist;
+  buildNodePackage = stdenv.lib.makeOverridable buildNodePackage;
+  buildNodeShell = stdenv.lib.makeOverridable buildNodeShell;
+}
diff --git a/libs.nix b/libs.nix
new file mode 100644 (file)
index 0000000..2ddfcbb
--- /dev/null
+++ b/libs.nix
@@ -0,0 +1,78 @@
+{ pkgs }:
+with pkgs;
+rec {
+  yarn2nixPackage = let
+    src = builtins.fetchGit {
+      url = "git://github.com/moretea/yarn2nix.git";
+      ref = "master";
+      rev = "780e33a07fd821e09ab5b05223ddb4ca15ac663f";
+    };
+  in
+    (callPackage src {}) // { inherit src; };
+
+  nodeEnv = import ./lib/node-env.nix;
+
+  fetchedGithub = path:
+    let
+      json = lib.importJSON path;
+    in rec {
+      version = json.tag;
+      name = "${json.meta.name}-${version}";
+      src = fetchFromGitHub json.github;
+    };
+
+  fetchedGit = path:
+    let
+      json = lib.importJSON path;
+    in rec {
+      version = json.tag;
+      name = "${json.meta.name}-${version}";
+      src = fetchgit json.git;
+    };
+
+  fetchedGitPrivate = path:
+    let
+      json = lib.importJSON path;
+    in rec {
+      version = json.tag;
+      name = "${json.meta.name}-${version}";
+      src = fetchgitPrivate json.git;
+    };
+
+  wrap = { paths ? [], vars ? {}, file ? null, script ? null, name ? "wrap" }:
+    assert file != null || script != null ||
+      abort "wrap needs 'file' or 'script' argument";
+    with rec {
+      set  = n: v: "--set ${pkgs.lib.escapeShellArg n} " +
+                    "${pkgs.lib.escapeShellArg v}";
+      args = (map (p: "--prefix PATH : ${p}/bin") paths) ++
+            (builtins.attrValues (pkgs.lib.mapAttrs set vars));
+    };
+    runCommand name
+      {
+        f           = if file == null then writeScript name script else file;
+        buildInputs = [ makeWrapper ];
+      }
+      ''
+        makeWrapper "$f" "$out" ${toString args}
+      '';
+
+  # This adds header colors to the builds, but it rebuilds the whole
+  # world from scratch, so only use it to debug!
+  # add it as postHook in derivations
+  immaePostHook = ''
+    header() {
+      echo -ne "\033[1;36m"
+      echo -n "$1"
+      echo -e "\033[0m"
+    }
+
+    echoCmd() {
+      printf "\033[1;34m%s:\033[0m" "$1"
+      shift
+      printf ' %q' "$@"
+      echo
+    }
+  '';
+
+} // (if builtins.pathExists ./lib/private then import ./lib/private else {})
diff --git a/modules/default.nix b/modules/default.nix
new file mode 100644 (file)
index 0000000..acb0bb5
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  myids = ./myids.nix;
+  secrets = ./secrets.nix;
+
+  webstats = ./webapps/webstats;
+  diaspora = ./webapps/diaspora.nix;
+  etherpad-lite = ./webapps/etherpad-lite.nix;
+  mastodon = ./webapps/mastodon.nix;
+  mediagoblin = ./webapps/mediagoblin.nix;
+  peertube = ./webapps/peertube.nix;
+
+  websites = ./websites;
+} // (if builtins.pathExists ./private then import ./private else {})
diff --git a/modules/myids.nix b/modules/myids.nix
new file mode 100644 (file)
index 0000000..4fb2626
--- /dev/null
@@ -0,0 +1,22 @@
+{ ... }:
+{
+  # Check that there is no clash with nixos/modules/misc/ids.nix
+  config = {
+    ids.uids = {
+      peertube = 394;
+      redis = 395;
+      nullmailer = 396;
+      mediagoblin = 397;
+      diaspora = 398;
+      mastodon = 399;
+    };
+    ids.gids = {
+      peertube = 394;
+      redis = 395;
+      nullmailer = 396;
+      mediagoblin = 397;
+      diaspora = 398;
+      mastodon = 399;
+    };
+  };
+}
diff --git a/modules/secrets.nix b/modules/secrets.nix
new file mode 100644 (file)
index 0000000..b282e56
--- /dev/null
@@ -0,0 +1,61 @@
+{ lib, pkgs, config, ... }:
+{
+  options.secrets = {
+    keys = lib.mkOption {
+      type = lib.types.listOf lib.types.unspecified;
+      default = [];
+      description = "Keys to upload to server";
+    };
+    location = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/secrets";
+      description = "Location where to put the keys";
+    };
+  };
+  config = let
+    location = config.secrets.location;
+    keys = config.secrets.keys;
+    empty = pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out && touch $out/done";
+    dumpKey = v: ''
+        mkdir -p secrets/$(dirname ${v.dest})
+        echo -n ${lib.strings.escapeShellArg v.text} > secrets/${v.dest}
+        cat >> mods <<EOF
+        ${v.user or "root"} ${v.group or "root"} ${v.permissions or "0600"} secrets/${v.dest}
+        EOF
+        '';
+    secrets = pkgs.runCommand "secrets.tar" {} ''
+      touch mods
+      tar --format=ustar --mtime='1970-01-01' -P --transform="s@${empty}@secrets@" -cf $out ${empty}/done
+      ${builtins.concatStringsSep "\n" (map dumpKey keys)}
+      cat mods | while read u g p k; do
+      tar --format=ustar --mtime='1970-01-01' --owner="$u" --group="$g" --mode="$p" --append -f $out "$k"
+      done
+      '';
+  in lib.mkIf (builtins.length keys > 0) {
+    system.activationScripts.secrets = {
+      deps = [ "users" "wrappers" ];
+      text = ''
+        install -m0750 -o root -g keys -d ${location}
+        if [ -f /run/keys/secrets.tar ]; then
+          if [ ! -f ${location}/currentSecrets ] || ! sha512sum -c --status "${location}/currentSecrets"; then
+            echo "rebuilding secrets"
+            rm -rf ${location}
+            install -m0750 -o root -g keys -d ${location}
+            ${pkgs.gnutar}/bin/tar --strip-components 1 -C ${location} -xf /run/keys/secrets.tar
+            sha512sum /run/keys/secrets.tar > ${location}/currentSecrets
+            find ${location} -type d -exec chown root:keys {} \; -exec chmod o-rx {} \;
+          fi
+        fi
+        '';
+    };
+    deployment.keys."secrets.tar" = {
+      permissions = "0400";
+      # keyFile below is not evaluated at build time by nixops, so the
+      # `secrets` path doesn’t necessarily exist when uploading the
+      # keys, and nixops is unhappy.
+      user = "root${builtins.substring 10000 1 secrets}";
+      group = "root";
+      keyFile = "${secrets}";
+    };
+  };
+}
diff --git a/modules/webapps/diaspora.nix b/modules/webapps/diaspora.nix
new file mode 100644 (file)
index 0000000..65599b7
--- /dev/null
@@ -0,0 +1,171 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "diaspora";
+  cfg = config.services.diaspora;
+
+  uid = config.ids.uids.diaspora;
+  gid = config.ids.gids.diaspora;
+in
+{
+  options.services.diaspora = {
+    enable = lib.mkEnableOption "Enable Diaspora’s service";
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "User account under which Diaspora runs";
+    };
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "Group under which Diaspora runs";
+    };
+    adminEmail = lib.mkOption {
+      type = lib.types.str;
+      example = "admin@example.com";
+      description = "Admin e-mail for Diaspora";
+    };
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Diaspora stores its data.
+      '';
+    };
+    socketsDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/run/${name}";
+      description = ''
+        The directory where Diaspora puts runtime files and sockets.
+        '';
+    };
+    configDir = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The configuration path for Diaspora.
+        '';
+    };
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.webapps.diaspora;
+      description = ''
+        Diaspora package to use.
+        '';
+    };
+    # Output variables
+    systemdStateDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if varDir is outside of /var/lib
+      default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+        lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+      description = ''
+      Adjusted Diaspora data directory for systemd
+      '';
+      readOnly = true;
+    };
+    systemdRuntimeDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if socketsDir is outside of /run
+      default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
+        lib.strings.removePrefix "/run/" cfg.socketsDir;
+      description = ''
+      Adjusted Diaspora sockets directory for systemd
+      '';
+      readOnly = true;
+    };
+    workdir = lib.mkOption {
+      type = lib.types.package;
+      default = cfg.package.override {
+        varDir = cfg.dataDir;
+        podmin_email = cfg.adminEmail;
+        config_dir = cfg.configDir;
+      };
+      description = ''
+        Adjusted diaspora package with overriden values
+        '';
+      readOnly = true;
+    };
+    sockets = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        rails = "${cfg.socketsDir}/diaspora.sock";
+        eye   = "${cfg.socketsDir}/eye.sock";
+      };
+      readOnly = true;
+      description = ''
+        Diaspora sockets
+        '';
+    };
+    pids = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        eye   = "${cfg.socketsDir}/eye.pid";
+      };
+      readOnly = true;
+      description = ''
+        Diaspora pids
+        '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
+      inherit name;
+      inherit uid;
+      group = cfg.group;
+      description = "Diaspora user";
+      home = cfg.dataDir;
+      packages = [ cfg.workdir.gems pkgs.nodejs cfg.workdir.gems.ruby ];
+      useDefaultShell = true;
+    });
+    users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
+      inherit name;
+      inherit gid;
+    });
+
+    systemd.services.diaspora = {
+      description = "Diaspora";
+      wantedBy = [ "multi-user.target" ];
+      after = [
+        "network.target" "redis.service" "postgresql.service"
+      ];
+      wants = [
+        "redis.service" "postgresql.service"
+      ];
+
+      environment.RAILS_ENV = "production";
+      environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
+      environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
+      environment.EYE_SOCK = cfg.sockets.eye;
+      environment.EYE_PID = cfg.pids.eye;
+
+      path = [ cfg.workdir.gems pkgs.nodejs cfg.workdir.gems.ruby pkgs.curl pkgs.which pkgs.gawk ];
+
+      preStart = ''
+        install -m 0755 -d ${cfg.dataDir}/uploads ${cfg.dataDir}/tmp ${cfg.dataDir}/log
+        install -m 0700 -d ${cfg.dataDir}/tmp/pids
+        if [ ! -f ${cfg.dataDir}/schedule.yml ]; then
+          echo "{}" > ${cfg.dataDir}/schedule.yml
+        fi
+        ./bin/bundle exec rails db:migrate
+      '';
+
+      script = ''
+        exec ${cfg.workdir}/script/server
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        PrivateTmp = true;
+        Restart = "always";
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        StateDirectory = cfg.systemdStateDirectory;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        StandardInput = "null";
+        KillMode = "control-group";
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+  };
+}
diff --git a/modules/webapps/etherpad-lite.nix b/modules/webapps/etherpad-lite.nix
new file mode 100644 (file)
index 0000000..7f0e2ed
--- /dev/null
@@ -0,0 +1,158 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "etherpad-lite";
+  cfg = config.services.etherpad-lite;
+
+  uid = config.ids.uids.etherpad-lite;
+  gid = config.ids.gids.etherpad-lite;
+in
+{
+  options.services.etherpad-lite = {
+    enable = lib.mkEnableOption "Enable Etherpad lite’s service";
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "User account under which Etherpad lite runs";
+    };
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "Group under which Etherpad lite runs";
+    };
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Etherpad lite stores its data.
+      '';
+    };
+    socketsDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/run/${name}";
+      description = ''
+        The directory where Etherpad lite stores its sockets.
+      '';
+    };
+    configFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The config file path for Etherpad lite.
+        '';
+    };
+    sessionKeyFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The Session key file path for Etherpad lite.
+        '';
+    };
+    apiKeyFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The API key file path for Etherpad lite.
+        '';
+    };
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.webapps.etherpad-lite;
+      description = ''
+        Etherpad lite package to use.
+        '';
+    };
+    modules = lib.mkOption {
+      type = lib.types.listOf lib.types.package;
+      default = [];
+      description = ''
+        Etherpad lite modules to use.
+        '';
+    };
+    # Output variables
+    workdir = lib.mkOption {
+      type = lib.types.package;
+      default = cfg.package.withModules cfg.modules;
+      description = ''
+      Adjusted Etherpad lite package with plugins
+      '';
+      readOnly = true;
+    };
+    systemdStateDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if varDir is outside of /var/lib
+      default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+        lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+      description = ''
+      Adjusted Etherpad lite data directory for systemd
+      '';
+      readOnly = true;
+    };
+    systemdRuntimeDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if socketsDir is outside of /run
+      default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
+        lib.strings.removePrefix "/run/" cfg.socketsDir;
+      description = ''
+      Adjusted Etherpad lite sockets directory for systemd
+      '';
+      readOnly = true;
+    };
+    sockets = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        node  = "${cfg.socketsDir}/etherpad-lite.sock";
+      };
+      readOnly = true;
+      description = ''
+        Etherpad lite sockets
+        '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    systemd.services.etherpad-lite = {
+      description = "Etherpad-lite";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "postgresql.service" ];
+      wants = [ "postgresql.service" ];
+
+      environment.NODE_ENV = "production";
+      environment.HOME = cfg.workdir;
+
+      path = [ pkgs.nodejs ];
+
+      script = ''
+        exec ${pkgs.nodejs}/bin/node ${cfg.workdir}/src/node/server.js \
+          --sessionkey ${cfg.sessionKeyFile} \
+          --apikey ${cfg.apiKeyFile} \
+          --settings ${cfg.configFile}
+      '';
+
+      postStart = ''
+        while [ ! -S ${cfg.sockets.node} ]; do
+          sleep 0.5
+        done
+        chmod a+w ${cfg.sockets.node}
+        '';
+      serviceConfig = {
+        DynamicUser = true;
+        User = cfg.user;
+        Group = cfg.group;
+        WorkingDirectory = cfg.workdir;
+        PrivateTmp = true;
+        NoNewPrivileges = true;
+        PrivateDevices = true;
+        ProtectHome = true;
+        ProtectControlGroups = true;
+        ProtectKernelModules = true;
+        Restart = "always";
+        Type = "simple";
+        TimeoutSec = 60;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        StateDirectory= cfg.systemdStateDirectory;
+        ExecStartPre = [
+          "+${pkgs.coreutils}/bin/install -d -m 0755 -o ${cfg.user} -g ${cfg.group} ${cfg.dataDir}/ep_initialized"
+          "+${pkgs.coreutils}/bin/chown -R ${cfg.user}:${cfg.group} ${cfg.dataDir} ${cfg.configFile} ${cfg.sessionKeyFile} ${cfg.apiKeyFile}"
+        ];
+      };
+    };
+
+  };
+}
diff --git a/modules/webapps/mastodon.nix b/modules/webapps/mastodon.nix
new file mode 100644 (file)
index 0000000..6255de9
--- /dev/null
@@ -0,0 +1,223 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "mastodon";
+  cfg = config.services.mastodon;
+
+  uid = config.ids.uids.mastodon;
+  gid = config.ids.gids.mastodon;
+in
+{
+  options.services.mastodon = {
+    enable = lib.mkEnableOption "Enable Mastodon’s service";
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "User account under which Mastodon runs";
+    };
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "Group under which Mastodon runs";
+    };
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Mastodon stores its data.
+      '';
+    };
+    socketsPrefix = lib.mkOption {
+      type = lib.types.string;
+      default = "live";
+      description = ''
+        The prefix to use for Mastodon sockets.
+        '';
+    };
+    socketsDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/run/${name}";
+      description = ''
+        The directory where Mastodon puts runtime files and sockets.
+        '';
+    };
+    configFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The configuration file path for Mastodon.
+        '';
+    };
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.webapps.mastodon;
+      description = ''
+        Mastodon package to use.
+        '';
+    };
+    # Output variables
+    workdir = lib.mkOption {
+      type = lib.types.package;
+      default = cfg.package.override { varDir = cfg.dataDir; };
+      description = ''
+      Adjusted mastodon package with overriden varDir
+      '';
+      readOnly = true;
+    };
+    systemdStateDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if varDir is outside of /var/lib
+      default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+        lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+      description = ''
+      Adjusted Mastodon data directory for systemd
+      '';
+      readOnly = true;
+    };
+    systemdRuntimeDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if socketsDir is outside of /run
+      default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
+        lib.strings.removePrefix "/run/" cfg.socketsDir;
+      description = ''
+      Adjusted Mastodon sockets directory for systemd
+      '';
+      readOnly = true;
+    };
+    sockets = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        node  = "${cfg.socketsDir}/${cfg.socketsPrefix}_node.sock";
+        rails = "${cfg.socketsDir}/${cfg.socketsPrefix}_puma.sock";
+      };
+      readOnly = true;
+      description = ''
+        Mastodon sockets
+        '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
+      inherit name;
+      inherit uid;
+      group = cfg.group;
+      description = "Mastodon user";
+      home = cfg.dataDir;
+      useDefaultShell = true;
+    });
+    users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
+      inherit name;
+      inherit gid;
+    });
+
+    systemd.services.mastodon-streaming = {
+      description = "Mastodon Streaming";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mastodon-web.service" ];
+
+      environment.NODE_ENV = "production";
+      environment.SOCKET = cfg.sockets.node;
+
+      path = [ pkgs.nodejs pkgs.bashInteractive ];
+
+      script = ''
+        exec npm run start
+      '';
+
+      postStart = ''
+        while [ ! -S $SOCKET ]; do
+          sleep 0.5
+        done
+        chmod a+w $SOCKET
+      '';
+
+      postStop = ''
+        rm $SOCKET
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        EnvironmentFile = cfg.configFile;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        StateDirectory = cfg.systemdStateDirectory;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        RuntimeDirectoryPreserve = "yes";
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+
+    systemd.services.mastodon-web = {
+      description = "Mastodon Web app";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+
+      environment.RAILS_ENV = "production";
+      environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
+      environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
+      environment.SOCKET = cfg.sockets.rails;
+
+      path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.file ];
+
+      preStart = ''
+        install -m 0755 -d ${cfg.dataDir}/tmp/cache
+        ./bin/bundle exec rails db:migrate
+      '';
+
+      script = ''
+        exec ./bin/bundle exec puma -C config/puma.rb
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        EnvironmentFile = cfg.configFile;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 60;
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        StateDirectory = cfg.systemdStateDirectory;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        RuntimeDirectoryPreserve = "yes";
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+
+    systemd.services.mastodon-sidekiq = {
+      description = "Mastodon Sidekiq";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mastodon-web.service" ];
+
+      environment.RAILS_ENV="production";
+      environment.BUNDLE_PATH = "${cfg.workdir.gems}/${cfg.workdir.gems.ruby.gemPath}";
+      environment.BUNDLE_GEMFILE = "${cfg.workdir.gems.confFiles}/Gemfile";
+      environment.DB_POOL="5";
+
+      path = [ cfg.workdir.gems cfg.workdir.gems.ruby pkgs.imagemagick pkgs.ffmpeg pkgs.file ];
+
+      script = ''
+        exec ./bin/bundle exec sidekiq -c 5 -q default -q mailers -q pull -q push
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        EnvironmentFile = cfg.configFile;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        StateDirectory = cfg.systemdStateDirectory;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        RuntimeDirectoryPreserve = "yes";
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+
+  };
+}
diff --git a/modules/webapps/mediagoblin.nix b/modules/webapps/mediagoblin.nix
new file mode 100644 (file)
index 0000000..78bbef6
--- /dev/null
@@ -0,0 +1,237 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "mediagoblin";
+  cfg = config.services.mediagoblin;
+
+  uid = config.ids.uids.mediagoblin;
+  gid = config.ids.gids.mediagoblin;
+
+  paste_local = pkgs.writeText "paste_local.ini" ''
+    [DEFAULT]
+    debug = false
+
+    [pipeline:main]
+    pipeline = mediagoblin
+
+    [app:mediagoblin]
+    use = egg:mediagoblin#app
+    config = ${cfg.configFile} ${cfg.workdir}/mediagoblin.ini
+    /mgoblin_static = ${cfg.workdir}/mediagoblin/static
+
+    [loggers]
+    keys = root
+
+    [handlers]
+    keys = console
+
+    [formatters]
+    keys = generic
+
+    [logger_root]
+    level = INFO
+    handlers = console
+
+    [handler_console]
+    class = StreamHandler
+    args = (sys.stderr,)
+    level = NOTSET
+    formatter = generic
+
+    [formatter_generic]
+    format = %(levelname)-7.7s [%(name)s] %(message)s
+
+    [filter:errors]
+    use = egg:mediagoblin#errors
+    debug = false
+
+    [server:main]
+    use = egg:waitress#main
+    unix_socket = ${cfg.sockets.paster}
+    unix_socket_perms = 777
+    url_scheme = https
+    '';
+in
+{
+  options.services.mediagoblin = {
+    enable = lib.mkEnableOption "Enable Mediagoblin’s service";
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "User account under which Mediagoblin runs";
+    };
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "Group under which Mediagoblin runs";
+    };
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Mediagoblin stores its data.
+      '';
+    };
+    socketsDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/run/${name}";
+      description = ''
+        The directory where Mediagoblin puts runtime files and sockets.
+        '';
+    };
+    configFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The configuration file path for Mediagoblin.
+        '';
+    };
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.webapps.mediagoblin;
+      description = ''
+        Mediagoblin package to use.
+        '';
+    };
+    plugins = lib.mkOption {
+      type = lib.types.listOf lib.types.package;
+      default = [];
+      description = ''
+        Mediagoblin plugins to use.
+        '';
+    };
+    # Output variables
+    workdir = lib.mkOption {
+      type = lib.types.package;
+      default = cfg.package.withPlugins cfg.plugins;
+      description = ''
+      Adjusted Mediagoblin package with plugins
+      '';
+      readOnly = true;
+    };
+    systemdStateDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if varDir is outside of /var/lib
+      default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+        lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+      description = ''
+      Adjusted Mediagoblin data directory for systemd
+      '';
+      readOnly = true;
+    };
+    systemdRuntimeDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if socketsDir is outside of /run
+      default = assert lib.strings.hasPrefix "/run/" cfg.socketsDir;
+        lib.strings.removePrefix "/run/" cfg.socketsDir;
+      description = ''
+      Adjusted Mediagoblin sockets directory for systemd
+      '';
+      readOnly = true;
+    };
+    sockets = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        paster = "${cfg.socketsDir}/mediagoblin.sock";
+      };
+      readOnly = true;
+      description = ''
+        Mediagoblin sockets
+        '';
+    };
+    pids = lib.mkOption {
+      type = lib.types.attrsOf lib.types.path;
+      default = {
+        paster = "${cfg.socketsDir}/mediagoblin.pid";
+        celery = "${cfg.socketsDir}/mediagoblin-celeryd.pid";
+      };
+      readOnly = true;
+      description = ''
+        Mediagoblin pid files
+        '';
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
+      inherit name;
+      inherit uid;
+      group = cfg.group;
+      description = "Mediagoblin user";
+      home = cfg.dataDir;
+      useDefaultShell = true;
+    });
+    users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
+      inherit name;
+      inherit gid;
+    });
+
+    systemd.services.mediagoblin-web = {
+      description = "Mediagoblin service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" ];
+      wants = [ "postgresql.service" "redis.service" ];
+
+      environment.SCRIPT_NAME = "/mediagoblin/";
+
+      script = ''
+        exec ./bin/paster serve \
+          ${paste_local} \
+          --pid-file=${cfg.pids.paster}
+        '';
+      preStop = ''
+        exec ./bin/paster serve \
+          --pid-file=${cfg.pids.paster} \
+          ${paste_local} stop
+        '';
+      preStart = ''
+        if [ -d ${cfg.dataDir}/plugin_static/ ]; then
+          rm ${cfg.dataDir}/plugin_static/coreplugin_basic_auth
+          ln -sf ${cfg.workdir}/mediagoblin/plugins/basic_auth/static ${cfg.dataDir}/plugin_static/coreplugin_basic_auth
+        fi
+        ./bin/gmg -cf ${cfg.configFile} dbupdate
+        '';
+
+      serviceConfig = {
+        User = cfg.user;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 15;
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        StateDirectory= cfg.systemdStateDirectory;
+        PIDFile = cfg.pids.paster;
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+
+    systemd.services.mediagoblin-celeryd = {
+      description = "Mediagoblin service";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "mediagoblin-web.service" ];
+
+      environment.MEDIAGOBLIN_CONFIG = cfg.configFile;
+      environment.CELERY_CONFIG_MODULE = "mediagoblin.init.celery.from_celery";
+
+      script = ''
+        exec ./bin/celery worker \
+          --logfile=${cfg.dataDir}/celery.log \
+          --loglevel=INFO
+        '';
+
+      serviceConfig = {
+        User = cfg.user;
+        PrivateTmp = true;
+        Restart = "always";
+        TimeoutSec = 60;
+        Type = "simple";
+        WorkingDirectory = cfg.workdir;
+        RuntimeDirectory = cfg.systemdRuntimeDirectory;
+        StateDirectory= cfg.systemdStateDirectory;
+        PIDFile = cfg.pids.celery;
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+  };
+}
diff --git a/modules/webapps/peertube.nix b/modules/webapps/peertube.nix
new file mode 100644 (file)
index 0000000..89dcc67
--- /dev/null
@@ -0,0 +1,105 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "peertube";
+  cfg = config.services.peertube;
+
+  uid = config.ids.uids.peertube;
+  gid = config.ids.gids.peertube;
+in
+{
+  options.services.peertube = {
+    enable = lib.mkEnableOption "Enable Peertube’s service";
+    user = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "User account under which Peertube runs";
+    };
+    group = lib.mkOption {
+      type = lib.types.str;
+      default = name;
+      description = "Group under which Peertube runs";
+    };
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Peertube stores its data.
+      '';
+    };
+    configFile = lib.mkOption {
+      type = lib.types.path;
+      description = ''
+        The configuration file path for Peertube.
+        '';
+    };
+    package = lib.mkOption {
+      type = lib.types.package;
+      default = pkgs.webapps.peertube;
+      description = ''
+        Peertube package to use.
+        '';
+    };
+    # Output variables
+    systemdStateDirectory = lib.mkOption {
+      type = lib.types.str;
+      # Use ReadWritePaths= instead if varDir is outside of /var/lib
+      default = assert lib.strings.hasPrefix "/var/lib/" cfg.dataDir;
+        lib.strings.removePrefix "/var/lib/" cfg.dataDir;
+      description = ''
+      Adjusted Peertube data directory for systemd
+      '';
+      readOnly = true;
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    users.users = lib.optionalAttrs (cfg.user == name) (lib.singleton {
+      inherit name;
+      inherit uid;
+      group = cfg.group;
+      description = "Peertube user";
+      home = cfg.dataDir;
+      useDefaultShell = true;
+    });
+    users.groups = lib.optionalAttrs (cfg.group == name) (lib.singleton {
+      inherit name;
+      inherit gid;
+    });
+
+    systemd.services.peertube = {
+      description = "Peertube";
+      wantedBy = [ "multi-user.target" ];
+      after = [ "network.target" "postgresql.service" ];
+      wants = [ "postgresql.service" ];
+
+      environment.NODE_CONFIG_DIR = "${cfg.dataDir}/config";
+      environment.NODE_ENV = "production";
+      environment.HOME = cfg.package;
+
+      path = [ pkgs.nodejs pkgs.bashInteractive pkgs.ffmpeg pkgs.openssl ];
+
+      script = ''
+        install -m 0750 -d ${cfg.dataDir}/config
+        ln -sf ${cfg.configFile} ${cfg.dataDir}/config/production.yaml
+        exec npm run start
+      '';
+
+      serviceConfig = {
+        User = cfg.user;
+        Group = cfg.group;
+        WorkingDirectory = cfg.package;
+        StateDirectory = cfg.systemdStateDirectory;
+        StateDirectoryMode = 0750;
+        PrivateTmp = true;
+        ProtectHome = true;
+        ProtectControlGroups = true;
+        Restart = "always";
+        Type = "simple";
+        TimeoutSec = 60;
+      };
+
+      unitConfig.RequiresMountsFor = cfg.dataDir;
+    };
+  };
+}
+
diff --git a/modules/webapps/webstats/default.nix b/modules/webapps/webstats/default.nix
new file mode 100644 (file)
index 0000000..924d72d
--- /dev/null
@@ -0,0 +1,81 @@
+{ lib, pkgs, config, ... }:
+let
+  name = "goaccess";
+  cfg = config.services.webstats;
+in {
+  options.services.webstats = {
+    dataDir = lib.mkOption {
+      type = lib.types.path;
+      default = "/var/lib/${name}";
+      description = ''
+        The directory where Goaccess stores its data.
+      '';
+    };
+    sites = lib.mkOption {
+      type = lib.types.listOf (lib.types.submodule {
+        options = {
+          conf = lib.mkOption {
+            type = lib.types.nullOr lib.types.path;
+            default = null;
+            description = ''
+              use custom goaccess configuration file instead of the
+              default one.
+              '';
+          };
+          name = lib.mkOption {
+            type = lib.types.string;
+            description  = ''
+              Domain name. Corresponds to the Apache file name and the
+              folder name in which the state will be saved.
+              '';
+          };
+        };
+      });
+      default = [];
+      description = "Sites to generate stats";
+    };
+  };
+
+  config = lib.mkIf (builtins.length cfg.sites > 0) {
+    users.users.root.packages = [
+      pkgs.goaccess
+    ];
+
+    services.cron = {
+      enable = true;
+      systemCronJobs = let
+        stats = domain: conf: let
+          config = if builtins.isNull conf
+            then pkgs.runCommand "goaccess.conf" {
+                dbPath = "${cfg.dataDir}/${domain}";
+              } "substituteAll ${./goaccess.conf} $out"
+            else conf;
+          d = pkgs.writeScriptBin "stats-${domain}" ''
+            #!${pkgs.stdenv.shell}
+            set -e
+            shopt -s nullglob
+            date_regex=$(LC_ALL=C date -d yesterday +'%d\/%b\/%Y')
+            TMPFILE=$(mktemp)
+            trap "rm -f $TMPFILE" EXIT
+
+            mkdir -p ${cfg.dataDir}/${domain}
+            cat /var/log/httpd/access-${domain}.log | sed -n "/\\[$date_regex/ p" > $TMPFILE
+            for i in /var/log/httpd/access-${domain}*.gz; do
+              zcat "$i" | sed -n "/\\[$date_regex/ p" >> $TMPFILE
+            done
+            ${pkgs.goaccess}/bin/goaccess $TMPFILE --no-progress -o ${cfg.dataDir}/${domain}/index.html -p ${config}
+            '';
+          in "${d}/bin/stats-${domain}";
+        allStats = sites: pkgs.writeScript "stats" ''
+          #!${pkgs.stdenv.shell}
+
+          mkdir -p ${cfg.dataDir}
+          ${builtins.concatStringsSep "\n" (map (v: stats v.name v.conf) sites)}
+          '';
+      in
+        [
+          "5 0 * * * root ${allStats cfg.sites}"
+        ];
+    };
+  };
+}
diff --git a/modules/webapps/webstats/goaccess.conf b/modules/webapps/webstats/goaccess.conf
new file mode 100644 (file)
index 0000000..4918988
--- /dev/null
@@ -0,0 +1,99 @@
+time-format %H:%M:%S
+date-format %d/%b/%Y
+
+#sur immae.eu
+#log-format %v %h %^[%d:%t %^] "%r" %s %b "%R" "%u" $^
+
+log-format VCOMBINED
+#= %v:%^ %h %^[%d:%t %^] "%r" %s %b "%R" "%u"
+
+html-prefs {"theme":"bright","layout":"vertical"}
+
+exclude-ip 188.165.209.148
+exclude-ip 178.33.252.96
+exclude-ip 2001:41d0:2:9c94::1
+exclude-ip 2001:41d0:2:9c94::
+exclude-ip 176.9.151.89
+exclude-ip 2a01:4f8:160:3445::
+exclude-ip 82.255.56.72
+
+no-query-string true
+
+keep-db-files true
+load-from-disk true
+db-path @dbPath@
+
+ignore-panel REFERRERS
+ignore-panel KEYPHRASES
+
+static-file .css
+static-file .js
+static-file .jpg
+static-file .png
+static-file .gif
+static-file .ico
+static-file .jpeg
+static-file .pdf
+static-file .csv
+static-file .mpeg
+static-file .mpg
+static-file .swf
+static-file .woff
+static-file .woff2
+static-file .xls
+static-file .xlsx
+static-file .doc
+static-file .docx
+static-file .ppt
+static-file .pptx
+static-file .txt
+static-file .zip
+static-file .ogg
+static-file .mp3
+static-file .mp4
+static-file .exe
+static-file .iso
+static-file .gz
+static-file .rar
+static-file .svg
+static-file .bmp
+static-file .tar
+static-file .tgz
+static-file .tiff
+static-file .tif
+static-file .ttf
+static-file .flv
+#static-file .less
+#static-file .ac3
+#static-file .avi
+#static-file .bz2
+#static-file .class
+#static-file .cue
+#static-file .dae
+#static-file .dat
+#static-file .dts
+#static-file .ejs
+#static-file .eot
+#static-file .eps
+#static-file .img
+#static-file .jar
+#static-file .map
+#static-file .mid
+#static-file .midi
+#static-file .ogv
+#static-file .webm
+#static-file .mkv
+#static-file .odp
+#static-file .ods
+#static-file .odt
+#static-file .otf
+#static-file .pict
+#static-file .pls
+#static-file .ps
+#static-file .qt
+#static-file .rm
+#static-file .svgz
+#static-file .wav
+#static-file .webp
+
+
diff --git a/modules/websites/default.nix b/modules/websites/default.nix
new file mode 100644 (file)
index 0000000..e57f505
--- /dev/null
@@ -0,0 +1,199 @@
+{ lib, config, ... }: with lib;
+let
+  cfg = config.services.websites;
+in
+{
+  options.services.websitesCerts = mkOption {
+    description = "Default websites configuration for certificates as accepted by acme";
+  };
+  options.services.websites = with types; mkOption {
+    default = {};
+    description = "Each type of website to enable will target a distinct httpd server";
+    type = attrsOf (submodule {
+      options = {
+        enable = mkEnableOption "Enable websites of this type";
+        adminAddr = mkOption {
+          type = str;
+          description = "Admin e-mail address of the instance";
+        };
+        httpdName = mkOption {
+          type = str;
+          description = "Name of the httpd instance to assign this type to";
+        };
+        ips = mkOption {
+          type = listOf string;
+          default = [];
+          description = "ips to listen to";
+        };
+        modules = mkOption {
+          type = listOf str;
+          default = [];
+          description = "Additional modules to load in Apache";
+        };
+        extraConfig = mkOption {
+          type = listOf lines;
+          default = [];
+          description = "Additional configuration to append to Apache";
+        };
+        nosslVhost = mkOption {
+          description = "A default nossl vhost for captive portals";
+          default = {};
+          type = submodule {
+            options = {
+              enable = mkEnableOption "Add default no-ssl vhost for this instance";
+              host = mkOption {
+                type = string;
+                description = "The hostname to use for this vhost";
+              };
+              root = mkOption {
+                type = path;
+                default = ./nosslVhost;
+                description = "The root folder to serve";
+              };
+              indexFile = mkOption {
+                type = string;
+                default = "index.html";
+                description = "The index file to show.";
+              };
+            };
+          };
+        };
+        fallbackVhost = mkOption {
+          description = "The fallback vhost that will be defined as first vhost in Apache";
+          type = submodule {
+            options = {
+              certName = mkOption { type = string; };
+              hosts    = mkOption { type = listOf string; };
+              root     = mkOption { type = nullOr path; };
+              extraConfig = mkOption { type = listOf lines; default = []; };
+            };
+          };
+        };
+        vhostConfs = mkOption {
+          default = {};
+          description = "List of vhosts to define for Apache";
+          type = attrsOf (submodule {
+            options = {
+              certName = mkOption { type = string; };
+              addToCerts = mkOption {
+                type = bool;
+                default = false;
+                description = "Use these to certificates. Is ignored (considered true) if certMainHost is not null";
+              };
+              certMainHost = mkOption {
+                type = nullOr string;
+                description = "Use that host as 'main host' for acme certs";
+                default = null;
+              };
+              hosts    = mkOption { type = listOf string; };
+              root     = mkOption { type = nullOr path; };
+              extraConfig = mkOption { type = listOf lines; default = []; };
+            };
+          });
+        };
+      };
+    });
+  };
+
+  config.services.httpd = let
+    redirectVhost = ips: { # Should go last, catchall http -> https redirect
+      listen = map (ip: { inherit ip; port = 80; }) ips;
+      hostName = "redirectSSL";
+      serverAliases = [ "*" ];
+      enableSSL = false;
+      logFormat = "combinedVhost";
+      documentRoot = "${config.security.acme.directory}/acme-challenge";
+      extraConfig = ''
+        RewriteEngine on
+        RewriteCond "%{REQUEST_URI}"   "!^/\.well-known"
+        RewriteRule ^(.+)              https://%{HTTP_HOST}$1  [R=301]
+        # To redirect in specific "VirtualHost *:80", do
+        #   RedirectMatch 301 ^/((?!\.well-known.*$).*)$ https://host/$1
+        # rather than rewrite
+      '';
+    };
+    nosslVhost = ips: cfg: {
+      listen = map (ip: { inherit ip; port = 80; }) ips;
+      hostName = cfg.host;
+      enableSSL = false;
+      logFormat = "combinedVhost";
+      documentRoot = cfg.root;
+      extraConfig = ''
+        <Directory ${cfg.root}>
+          DirectoryIndex ${cfg.indexFile}
+          AllowOverride None
+          Require all granted
+
+          RewriteEngine on
+          RewriteRule ^/(.+)   /   [L]
+        </Directory>
+        '';
+    };
+    toVhost = ips: vhostConf: {
+      enableSSL = true;
+      sslServerCert = "${config.security.acme.directory}/${vhostConf.certName}/cert.pem";
+      sslServerKey = "${config.security.acme.directory}/${vhostConf.certName}/key.pem";
+      sslServerChain = "${config.security.acme.directory}/${vhostConf.certName}/chain.pem";
+      logFormat = "combinedVhost";
+      listen = map (ip: { inherit ip; port = 443; }) ips;
+      hostName = builtins.head vhostConf.hosts;
+      serverAliases = builtins.tail vhostConf.hosts or [];
+      documentRoot = vhostConf.root;
+      extraConfig = builtins.concatStringsSep "\n" vhostConf.extraConfig;
+    };
+  in attrsets.mapAttrs' (name: icfg: attrsets.nameValuePair
+    icfg.httpdName (mkIf icfg.enable {
+      enable = true;
+      listen = map (ip: { inherit ip; port = 443; }) icfg.ips;
+      stateDir = "/run/httpd_${name}";
+      logPerVirtualHost = true;
+      multiProcessingModule = "worker";
+      inherit (icfg) adminAddr;
+      logFormat = "combinedVhost";
+      extraModules = lists.unique icfg.modules;
+      extraConfig = builtins.concatStringsSep "\n" icfg.extraConfig;
+      virtualHosts = [ (toVhost icfg.ips icfg.fallbackVhost) ]
+        ++ optionals (icfg.nosslVhost.enable) [ (nosslVhost icfg.ips icfg.nosslVhost) ]
+        ++ (attrsets.mapAttrsToList (n: v: toVhost icfg.ips v) icfg.vhostConfs)
+        ++ [ (redirectVhost icfg.ips) ];
+    })
+  ) cfg;
+
+  config.security.acme.certs = let
+    typesToManage = attrsets.filterAttrs (k: v: v.enable) cfg;
+    flatVhosts = lists.flatten (attrsets.mapAttrsToList (k: v:
+      attrValues v.vhostConfs
+    ) typesToManage);
+    groupedCerts = attrsets.filterAttrs
+      (_: group: builtins.any (v: v.addToCerts || !isNull v.certMainHost) group)
+      (lists.groupBy (v: v.certName) flatVhosts);
+    groupToDomain = group:
+      let
+        nonNull = builtins.filter (v: !isNull v.certMainHost) group;
+        domains = lists.unique (map (v: v.certMainHost) nonNull);
+      in
+        if builtins.length domains == 0
+          then null
+          else assert (builtins.length domains == 1); (elemAt domains 0);
+    extraDomains = group:
+      let
+        mainDomain = groupToDomain group;
+      in
+        lists.remove mainDomain (
+          lists.unique (
+            lists.flatten (map (c: optionals (c.addToCerts || !isNull c.certMainHost) c.hosts) group)
+          )
+        );
+  in attrsets.mapAttrs (k: g:
+    if (!isNull (groupToDomain g))
+    then config.services.websitesCerts // {
+      domain = groupToDomain g;
+      extraDomains = builtins.listToAttrs (
+        map (d: attrsets.nameValuePair d null) (extraDomains g));
+    }
+    else {
+      extraDomains = builtins.listToAttrs (
+        map (d: attrsets.nameValuePair d null) (extraDomains g));
+    }
+  ) groupedCerts;
+}
diff --git a/modules/websites/httpd-service-builder.nix b/modules/websites/httpd-service-builder.nix
new file mode 100644 (file)
index 0000000..d049202
--- /dev/null
@@ -0,0 +1,746 @@
+# to help backporting this builder should stay as close as possible to
+# nixos/modules/services/web-servers/apache-httpd/default.nix
+{ httpdName, withUsers ? true }:
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  mainCfg = config.services.httpd."${httpdName}";
+
+  httpd = mainCfg.package.out;
+
+  version24 = !versionOlder httpd.version "2.4";
+
+  httpdConf = mainCfg.configFile;
+
+  php = mainCfg.phpPackage.override { apacheHttpd = httpd.dev; /* otherwise it only gets .out */ };
+
+  phpMajorVersion = head (splitString "." php.version);
+
+  mod_perl = pkgs.apacheHttpdPackages.mod_perl.override { apacheHttpd = httpd; };
+
+  defaultListen = cfg: if cfg.enableSSL
+    then [{ip = "*"; port = 443;}]
+    else [{ip = "*"; port = 80;}];
+
+  getListen = cfg:
+    let list = (lib.optional (cfg.port != 0) {ip = "*"; port = cfg.port;}) ++ cfg.listen;
+    in if list == []
+        then defaultListen cfg
+        else list;
+
+  listenToString = l: "${l.ip}:${toString l.port}";
+
+  extraModules = attrByPath ["extraModules"] [] mainCfg;
+  extraForeignModules = filter isAttrs extraModules;
+  extraApacheModules = filter isString extraModules;
+
+
+  makeServerInfo = cfg: {
+    # Canonical name must not include a trailing slash.
+    canonicalNames =
+      let defaultPort = (head (defaultListen cfg)).port; in
+      map (port:
+        (if cfg.enableSSL then "https" else "http") + "://" +
+        cfg.hostName +
+        (if port != defaultPort then ":${toString port}" else "")
+        ) (map (x: x.port) (getListen cfg));
+
+    # Admin address: inherit from the main server if not specified for
+    # a virtual host.
+    adminAddr = if cfg.adminAddr != null then cfg.adminAddr else mainCfg.adminAddr;
+
+    vhostConfig = cfg;
+    serverConfig = mainCfg;
+    fullConfig = config; # machine config
+  };
+
+
+  allHosts = [mainCfg] ++ mainCfg.virtualHosts;
+
+
+  callSubservices = serverInfo: defs:
+    let f = svc:
+      let
+        svcFunction =
+          if svc ? function then svc.function
+          # instead of using serviceType="mediawiki"; you can copy mediawiki.nix to any location outside nixpkgs, modify it at will, and use serviceExpression=./mediawiki.nix;
+          else if svc ? serviceExpression then import (toString svc.serviceExpression)
+          else import (toString "${toString ./.}/${if svc ? serviceType then svc.serviceType else svc.serviceName}.nix");
+        config = (evalModules
+          { modules = [ { options = res.options; config = svc.config or svc; } ];
+            check = false;
+          }).config;
+        defaults = {
+          extraConfig = "";
+          extraModules = [];
+          extraModulesPre = [];
+          extraPath = [];
+          extraServerPath = [];
+          globalEnvVars = [];
+          robotsEntries = "";
+          startupScript = "";
+          enablePHP = false;
+          enablePerl = false;
+          phpOptions = "";
+          options = {};
+          documentRoot = null;
+        };
+        res = defaults // svcFunction { inherit config lib pkgs serverInfo php; };
+      in res;
+    in map f defs;
+
+
+  # !!! callSubservices is expensive
+  subservicesFor = cfg: callSubservices (makeServerInfo cfg) cfg.extraSubservices;
+
+  mainSubservices = subservicesFor mainCfg;
+
+  allSubservices = mainSubservices ++ concatMap subservicesFor mainCfg.virtualHosts;
+
+
+  enableSSL = any (vhost: vhost.enableSSL) allHosts;
+
+
+  # Names of modules from ${httpd}/modules that we want to load.
+  apacheModules =
+    [ # HTTP authentication mechanisms: basic and digest.
+      "auth_basic" "auth_digest"
+
+      # Authentication: is the user who he claims to be?
+      "authn_file" "authn_dbm" "authn_anon"
+      (if version24 then "authn_core" else "authn_alias")
+
+      # Authorization: is the user allowed access?
+      "authz_user" "authz_groupfile" "authz_host"
+
+      # Other modules.
+      "ext_filter" "include" "log_config" "env" "mime_magic"
+      "cern_meta" "expires" "headers" "usertrack" /* "unique_id" */ "setenvif"
+      "mime" "dav" "status" "autoindex" "asis" "info" "dav_fs"
+      "vhost_alias" "negotiation" "dir" "imagemap" "actions" "speling"
+      "userdir" "alias" "rewrite" "proxy" "proxy_http"
+    ]
+    ++ optionals version24 [
+      "mpm_${mainCfg.multiProcessingModule}"
+      "authz_core"
+      "unixd"
+      "cache" "cache_disk"
+      "slotmem_shm"
+      "socache_shmcb"
+      # For compatibility with old configurations, the new module mod_access_compat is provided.
+      "access_compat"
+    ]
+    ++ (if mainCfg.multiProcessingModule == "prefork" then [ "cgi" ] else [ "cgid" ])
+    ++ optional enableSSL "ssl"
+    ++ extraApacheModules;
+
+
+  allDenied = if version24 then ''
+    Require all denied
+  '' else ''
+    Order deny,allow
+    Deny from all
+  '';
+
+  allGranted = if version24 then ''
+    Require all granted
+  '' else ''
+    Order allow,deny
+    Allow from all
+  '';
+
+
+  loggingConf = (if mainCfg.logFormat != "none" then ''
+    ErrorLog ${mainCfg.logDir}/error.log
+
+    LogLevel notice
+
+    LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+    LogFormat "%h %l %u %t \"%r\" %>s %b" common
+    LogFormat "%{Referer}i -> %U" referer
+    LogFormat "%{User-agent}i" agent
+
+    CustomLog ${mainCfg.logDir}/access.log ${mainCfg.logFormat}
+  '' else ''
+    ErrorLog /dev/null
+  '');
+
+
+  browserHacks = ''
+    BrowserMatch "Mozilla/2" nokeepalive
+    BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0
+    BrowserMatch "RealPlayer 4\.0" force-response-1.0
+    BrowserMatch "Java/1\.0" force-response-1.0
+    BrowserMatch "JDK/1\.0" force-response-1.0
+    BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully
+    BrowserMatch "^WebDrive" redirect-carefully
+    BrowserMatch "^WebDAVFS/1.[012]" redirect-carefully
+    BrowserMatch "^gnome-vfs" redirect-carefully
+  '';
+
+
+  sslConf = ''
+    SSLSessionCache ${if version24 then "shmcb" else "shm"}:${mainCfg.stateDir}/ssl_scache(512000)
+
+    ${if version24 then "Mutex" else "SSLMutex"} posixsem
+
+    SSLRandomSeed startup builtin
+    SSLRandomSeed connect builtin
+
+    SSLProtocol ${mainCfg.sslProtocols}
+    SSLCipherSuite ${mainCfg.sslCiphers}
+    SSLHonorCipherOrder on
+  '';
+
+
+  mimeConf = ''
+    TypesConfig ${httpd}/conf/mime.types
+
+    AddType application/x-x509-ca-cert .crt
+    AddType application/x-pkcs7-crl    .crl
+    AddType application/x-httpd-php    .php .phtml
+
+    <IfModule mod_mime_magic.c>
+        MIMEMagicFile ${httpd}/conf/magic
+    </IfModule>
+  '';
+
+
+  perServerConf = isMainServer: cfg: let
+
+    serverInfo = makeServerInfo cfg;
+
+    subservices = callSubservices serverInfo cfg.extraSubservices;
+
+    maybeDocumentRoot = fold (svc: acc:
+      if acc == null then svc.documentRoot else assert svc.documentRoot == null; acc
+    ) null ([ cfg ] ++ subservices);
+
+    documentRoot = if maybeDocumentRoot != null then maybeDocumentRoot else
+      pkgs.runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out";
+
+    documentRootConf = ''
+      DocumentRoot "${documentRoot}"
+
+      <Directory "${documentRoot}">
+          Options Indexes FollowSymLinks
+          AllowOverride None
+          ${allGranted}
+      </Directory>
+    '';
+
+    robotsTxt =
+      concatStringsSep "\n" (filter (x: x != "") (
+        # If this is a vhost, the include the entries for the main server as well.
+        (if isMainServer then [] else [mainCfg.robotsEntries] ++ map (svc: svc.robotsEntries) mainSubservices)
+        ++ [cfg.robotsEntries]
+        ++ (map (svc: svc.robotsEntries) subservices)));
+
+  in ''
+    ${concatStringsSep "\n" (map (n: "ServerName ${n}") serverInfo.canonicalNames)}
+
+    ${concatMapStrings (alias: "ServerAlias ${alias}\n") cfg.serverAliases}
+
+    ${if cfg.sslServerCert != null then ''
+      SSLCertificateFile ${cfg.sslServerCert}
+      SSLCertificateKeyFile ${cfg.sslServerKey}
+      ${if cfg.sslServerChain != null then ''
+        SSLCertificateChainFile ${cfg.sslServerChain}
+      '' else ""}
+    '' else ""}
+
+    ${if cfg.enableSSL then ''
+      SSLEngine on
+    '' else if enableSSL then /* i.e., SSL is enabled for some host, but not this one */
+    ''
+      SSLEngine off
+    '' else ""}
+
+    ${if isMainServer || cfg.adminAddr != null then ''
+      ServerAdmin ${cfg.adminAddr}
+    '' else ""}
+
+    ${if !isMainServer && mainCfg.logPerVirtualHost then ''
+      ErrorLog ${mainCfg.logDir}/error-${cfg.hostName}.log
+      CustomLog ${mainCfg.logDir}/access-${cfg.hostName}.log ${cfg.logFormat}
+    '' else ""}
+
+    ${optionalString (robotsTxt != "") ''
+      Alias /robots.txt ${pkgs.writeText "robots.txt" robotsTxt}
+    ''}
+
+    ${if isMainServer || maybeDocumentRoot != null then documentRootConf else ""}
+
+    ${if cfg.enableUserDir then ''
+
+      UserDir public_html
+      UserDir disabled root
+
+      <Directory "/home/*/public_html">
+          AllowOverride FileInfo AuthConfig Limit Indexes
+          Options MultiViews Indexes SymLinksIfOwnerMatch IncludesNoExec
+          <Limit GET POST OPTIONS>
+              ${allGranted}
+          </Limit>
+          <LimitExcept GET POST OPTIONS>
+              ${allDenied}
+          </LimitExcept>
+      </Directory>
+
+    '' else ""}
+
+    ${if cfg.globalRedirect != null && cfg.globalRedirect != "" then ''
+      RedirectPermanent / ${cfg.globalRedirect}
+    '' else ""}
+
+    ${
+      let makeFileConf = elem: ''
+            Alias ${elem.urlPath} ${elem.file}
+          '';
+      in concatMapStrings makeFileConf cfg.servedFiles
+    }
+
+    ${
+      let makeDirConf = elem: ''
+            Alias ${elem.urlPath} ${elem.dir}/
+            <Directory ${elem.dir}>
+                Options +Indexes
+                ${allGranted}
+                AllowOverride All
+            </Directory>
+          '';
+      in concatMapStrings makeDirConf cfg.servedDirs
+    }
+
+    ${concatMapStrings (svc: svc.extraConfig) subservices}
+
+    ${cfg.extraConfig}
+  '';
+
+
+  confFile = pkgs.writeText "httpd.conf" ''
+
+    ServerRoot ${httpd}
+
+    ${optionalString version24 ''
+      DefaultRuntimeDir ${mainCfg.stateDir}/runtime
+    ''}
+
+    PidFile ${mainCfg.stateDir}/httpd.pid
+
+    ${optionalString (mainCfg.multiProcessingModule != "prefork") ''
+      # mod_cgid requires this.
+      ScriptSock ${mainCfg.stateDir}/cgisock
+    ''}
+
+    <IfModule prefork.c>
+        MaxClients           ${toString mainCfg.maxClients}
+        MaxRequestsPerChild  ${toString mainCfg.maxRequestsPerChild}
+    </IfModule>
+
+    ${let
+        listen = concatMap getListen allHosts;
+        toStr = listen: "Listen ${listenToString listen}\n";
+        uniqueListen = uniqList {inputList = map toStr listen;};
+      in concatStrings uniqueListen
+    }
+
+    User ${mainCfg.user}
+    Group ${mainCfg.group}
+
+    ${let
+        load = {name, path}: "LoadModule ${name}_module ${path}\n";
+        allModules =
+          concatMap (svc: svc.extraModulesPre) allSubservices
+          ++ map (name: {inherit name; path = "${httpd}/modules/mod_${name}.so";}) apacheModules
+          ++ optional mainCfg.enableMellon { name = "auth_mellon"; path = "${pkgs.apacheHttpdPackages.mod_auth_mellon}/modules/mod_auth_mellon.so"; }
+          ++ optional enablePHP { name = "php${phpMajorVersion}"; path = "${php}/modules/libphp${phpMajorVersion}.so"; }
+          ++ optional enablePerl { name = "perl"; path = "${mod_perl}/modules/mod_perl.so"; }
+          ++ concatMap (svc: svc.extraModules) allSubservices
+          ++ extraForeignModules;
+      in concatMapStrings load allModules
+    }
+
+    AddHandler type-map var
+
+    <Files ~ "^\.ht">
+        ${allDenied}
+    </Files>
+
+    ${mimeConf}
+    ${loggingConf}
+    ${browserHacks}
+
+    Include ${httpd}/conf/extra/httpd-default.conf
+    Include ${httpd}/conf/extra/httpd-autoindex.conf
+    Include ${httpd}/conf/extra/httpd-multilang-errordoc.conf
+    Include ${httpd}/conf/extra/httpd-languages.conf
+
+    TraceEnable off
+
+    ${if enableSSL then sslConf else ""}
+
+    # Fascist default - deny access to everything.
+    <Directory />
+        Options FollowSymLinks
+        AllowOverride None
+        ${allDenied}
+    </Directory>
+
+    # Generate directives for the main server.
+    ${perServerConf true mainCfg}
+
+    # Always enable virtual hosts; it doesn't seem to hurt.
+    ${let
+        listen = concatMap getListen allHosts;
+        uniqueListen = uniqList {inputList = listen;};
+        directives = concatMapStrings (listen: "NameVirtualHost ${listenToString listen}\n") uniqueListen;
+      in optionalString (!version24) directives
+    }
+
+    ${let
+        makeVirtualHost = vhost: ''
+          <VirtualHost ${concatStringsSep " " (map listenToString (getListen vhost))}>
+              ${perServerConf false vhost}
+          </VirtualHost>
+        '';
+      in concatMapStrings makeVirtualHost mainCfg.virtualHosts
+    }
+  '';
+
+
+  enablePHP = mainCfg.enablePHP || any (svc: svc.enablePHP) allSubservices;
+
+  enablePerl = mainCfg.enablePerl || any (svc: svc.enablePerl) allSubservices;
+
+
+  # Generate the PHP configuration file.  Should probably be factored
+  # out into a separate module.
+  phpIni = pkgs.runCommand "php.ini"
+    { options = concatStringsSep "\n"
+        ([ mainCfg.phpOptions ] ++ (map (svc: svc.phpOptions) allSubservices));
+      preferLocalBuild = true;
+    }
+    ''
+      cat ${php}/etc/php.ini > $out
+      echo "$options" >> $out
+    '';
+
+in
+
+
+{
+
+  ###### interface
+
+  options = {
+
+    services.httpd."${httpdName}" = {
+
+      enable = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Apache HTTP Server.";
+      };
+
+      package = mkOption {
+        type = types.package;
+        default = pkgs.apacheHttpd;
+        defaultText = "pkgs.apacheHttpd";
+        description = ''
+          Overridable attribute of the Apache HTTP Server package to use.
+        '';
+      };
+
+      configFile = mkOption {
+        type = types.path;
+        default = confFile;
+        defaultText = "confFile";
+        example = literalExample ''pkgs.writeText "httpd.conf" "# my custom config file ..."'';
+        description = ''
+          Override the configuration file used by Apache. By default,
+          NixOS generates one automatically.
+        '';
+      };
+
+      extraConfig = mkOption {
+        type = types.lines;
+        default = "";
+        description = ''
+          Cnfiguration lines appended to the generated Apache
+          configuration file. Note that this mechanism may not work
+          when <option>configFile</option> is overridden.
+        '';
+      };
+
+      extraModules = mkOption {
+        type = types.listOf types.unspecified;
+        default = [];
+        example = literalExample ''[ "proxy_connect" { name = "php5"; path = "''${pkgs.php}/modules/libphp5.so"; } ]'';
+        description = ''
+          Additional Apache modules to be used.  These can be
+          specified as a string in the case of modules distributed
+          with Apache, or as an attribute set specifying the
+          <varname>name</varname> and <varname>path</varname> of the
+          module.
+        '';
+      };
+
+      logPerVirtualHost = mkOption {
+        type = types.bool;
+        default = false;
+        description = ''
+          If enabled, each virtual host gets its own
+          <filename>access.log</filename> and
+          <filename>error.log</filename>, namely suffixed by the
+          <option>hostName</option> of the virtual host.
+        '';
+      };
+
+      user = mkOption {
+        type = types.str;
+        default = "wwwrun";
+        description = ''
+          User account under which httpd runs.  The account is created
+          automatically if it doesn't exist.
+        '';
+      };
+
+      group = mkOption {
+        type = types.str;
+        default = "wwwrun";
+        description = ''
+          Group under which httpd runs.  The account is created
+          automatically if it doesn't exist.
+        '';
+      };
+
+      logDir = mkOption {
+        type = types.path;
+        default = "/var/log/httpd";
+        description = ''
+          Directory for Apache's log files.  It is created automatically.
+        '';
+      };
+
+      stateDir = mkOption {
+        type = types.path;
+        default = "/run/httpd";
+        description = ''
+          Directory for Apache's transient runtime state (such as PID
+          files).  It is created automatically.  Note that the default,
+          <filename>/run/httpd</filename>, is deleted at boot time.
+        '';
+      };
+
+      virtualHosts = mkOption {
+        type = types.listOf (types.submodule (
+          { options = import <nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix> {
+              inherit lib;
+              forMainServer = false;
+            };
+          }));
+        default = [];
+        example = [
+          { hostName = "foo";
+            documentRoot = "/data/webroot-foo";
+          }
+          { hostName = "bar";
+            documentRoot = "/data/webroot-bar";
+          }
+        ];
+        description = ''
+          Specification of the virtual hosts served by Apache.  Each
+          element should be an attribute set specifying the
+          configuration of the virtual host.  The available options
+          are the non-global options permissible for the main host.
+        '';
+      };
+
+      enableMellon = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the mod_auth_mellon module.";
+      };
+
+      enablePHP = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the PHP module.";
+      };
+
+      phpPackage = mkOption {
+        type = types.package;
+        default = pkgs.php;
+        defaultText = "pkgs.php";
+        description = ''
+          Overridable attribute of the PHP package to use.
+        '';
+      };
+
+      enablePerl = mkOption {
+        type = types.bool;
+        default = false;
+        description = "Whether to enable the Perl module (mod_perl).";
+      };
+
+      phpOptions = mkOption {
+        type = types.lines;
+        default = "";
+        example =
+          ''
+            date.timezone = "CET"
+          '';
+        description =
+          "Options appended to the PHP configuration file <filename>php.ini</filename>.";
+      };
+
+      multiProcessingModule = mkOption {
+        type = types.str;
+        default = "prefork";
+        example = "worker";
+        description =
+          ''
+            Multi-processing module to be used by Apache.  Available
+            modules are <literal>prefork</literal> (the default;
+            handles each request in a separate child process),
+            <literal>worker</literal> (hybrid approach that starts a
+            number of child processes each running a number of
+            threads) and <literal>event</literal> (a recent variant of
+            <literal>worker</literal> that handles persistent
+            connections more efficiently).
+          '';
+      };
+
+      maxClients = mkOption {
+        type = types.int;
+        default = 150;
+        example = 8;
+        description = "Maximum number of httpd processes (prefork)";
+      };
+
+      maxRequestsPerChild = mkOption {
+        type = types.int;
+        default = 0;
+        example = 500;
+        description =
+          "Maximum number of httpd requests answered per httpd child (prefork), 0 means unlimited";
+      };
+
+      sslCiphers = mkOption {
+        type = types.str;
+        default = "HIGH:!aNULL:!MD5:!EXP";
+        description = "Cipher Suite available for negotiation in SSL proxy handshake.";
+      };
+
+      sslProtocols = mkOption {
+        type = types.str;
+        default = "All -SSLv2 -SSLv3 -TLSv1";
+        example = "All -SSLv2 -SSLv3";
+        description = "Allowed SSL/TLS protocol versions.";
+      };
+    }
+
+    # Include the options shared between the main server and virtual hosts.
+    // (import <nixpkgs/nixos/modules/services/web-servers/apache-httpd/per-server-options.nix> {
+      inherit lib;
+      forMainServer = true;
+    });
+
+  };
+
+
+  ###### implementation
+
+  config = mkIf config.services.httpd."${httpdName}".enable {
+
+    assertions = [ { assertion = mainCfg.enableSSL == true
+                               -> mainCfg.sslServerCert != null
+                                    && mainCfg.sslServerKey != null;
+                     message = "SSL is enabled for httpd, but sslServerCert and/or sslServerKey haven't been specified."; }
+                 ];
+
+    warnings = map (cfg: ''apache-httpd's port option is deprecated. Use listen = [{/*ip = "*"; */ port = ${toString cfg.port};}]; instead'' ) (lib.filter (cfg: cfg.port != 0) allHosts);
+
+    users.users = optionalAttrs (withUsers && mainCfg.user == "wwwrun") (singleton
+      { name = "wwwrun";
+        group = mainCfg.group;
+        description = "Apache httpd user";
+        uid = config.ids.uids.wwwrun;
+      });
+
+    users.groups = optionalAttrs (withUsers && mainCfg.group == "wwwrun") (singleton
+      { name = "wwwrun";
+        gid = config.ids.gids.wwwrun;
+      });
+
+    environment.systemPackages = [httpd] ++ concatMap (svc: svc.extraPath) allSubservices;
+
+    services.httpd."${httpdName}".phpOptions =
+      ''
+        ; Needed for PHP's mail() function.
+        sendmail_path = sendmail -t -i
+
+        ; Don't advertise PHP
+        expose_php = off
+      '' + optionalString (!isNull config.time.timeZone) ''
+
+        ; Apparently PHP doesn't use $TZ.
+        date.timezone = "${config.time.timeZone}"
+      '';
+
+    systemd.services."httpd${httpdName}" =
+      { description = "Apache HTTPD";
+
+        wantedBy = [ "multi-user.target" ];
+        wants = [ "keys.target" ];
+        after = [ "network.target" "fs.target" "postgresql.service" "keys.target" ];
+
+        path =
+          [ httpd pkgs.coreutils pkgs.gnugrep ]
+          ++ optional enablePHP pkgs.system-sendmail # Needed for PHP's mail() function.
+          ++ concatMap (svc: svc.extraServerPath) allSubservices;
+
+        environment =
+          optionalAttrs enablePHP { PHPRC = phpIni; }
+          // optionalAttrs mainCfg.enableMellon { LD_LIBRARY_PATH  = "${pkgs.xmlsec}/lib"; }
+          // (listToAttrs (concatMap (svc: svc.globalEnvVars) allSubservices));
+
+        preStart =
+          ''
+            mkdir -m 0750 -p ${mainCfg.stateDir}
+            [ $(id -u) != 0 ] || chown root.${mainCfg.group} ${mainCfg.stateDir}
+            ${optionalString version24 ''
+              mkdir -m 0750 -p "${mainCfg.stateDir}/runtime"
+              [ $(id -u) != 0 ] || chown root.${mainCfg.group} "${mainCfg.stateDir}/runtime"
+            ''}
+            mkdir -m 0700 -p ${mainCfg.logDir}
+
+            # Get rid of old semaphores.  These tend to accumulate across
+            # server restarts, eventually preventing it from restarting
+            # successfully.
+            for i in $(${pkgs.utillinux}/bin/ipcs -s | grep ' ${mainCfg.user} ' | cut -f2 -d ' '); do
+                ${pkgs.utillinux}/bin/ipcrm -s $i
+            done
+
+            # Run the startup hooks for the subservices.
+            for i in ${toString (map (svn: svn.startupScript) allSubservices)}; do
+                echo Running Apache startup hook $i...
+                $i
+            done
+          '';
+
+        serviceConfig.ExecStart = "@${httpd}/bin/httpd httpd -f ${httpdConf}";
+        serviceConfig.ExecStop = "${httpd}/bin/httpd -f ${httpdConf} -k graceful-stop";
+        serviceConfig.ExecReload = "${httpd}/bin/httpd -f ${httpdConf} -k graceful";
+        serviceConfig.Type = "forking";
+        serviceConfig.PIDFile = "${mainCfg.stateDir}/httpd.pid";
+        serviceConfig.Restart = "always";
+        serviceConfig.RestartSec = "5s";
+      };
+
+  };
+}
diff --git a/modules/websites/nosslVhost/index.html b/modules/websites/nosslVhost/index.html
new file mode 100644 (file)
index 0000000..4401a80
--- /dev/null
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>No SSL site</title>
+  </head>
+  <body>
+    <h1>No SSL on this site</h1>
+    <p>Use for wifi networks with login page that doesn't work well with
+    https.</p>
+  </body>
+</html>
diff --git a/nix_path_env b/nix_path_env
new file mode 100644 (file)
index 0000000..901cd69
--- /dev/null
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+if [ -z "$NIXOPS_DEPLOYMENT" ]; then
+  # This will automatically upgrade to latest version at each build
+  nixpkgs="https://nixos.org/channels/nixos-19.03/nixexprs.tar.xz"
+else
+  nixpkgs="https://releases.nixos.org/nixos/19.03/nixos-19.03.172530.096e2f137b6/nixexprs.tar.xz"
+fi
+nixpkgsPrevious="$nixpkgs"
+nixpkgsNext="$nixpkgs"
+export NIX_PATH="nixpkgs=$nixpkgs:nixpkgsNext=$nixpkgsNext:nixpkgsPrevious=$nixpkgsPrevious"
diff --git a/overlays/bitlbee/bitlbee_long_nicks.patch b/overlays/bitlbee/bitlbee_long_nicks.patch
new file mode 100644 (file)
index 0000000..70be092
--- /dev/null
@@ -0,0 +1,56 @@
+diff --git a/bitlbee.h b/bitlbee.h
+index 17ab2979..5858277e 100644
+--- a/bitlbee.h
++++ b/bitlbee.h
+@@ -121,7 +121,7 @@ extern "C" {
+ #define CONTROL_TOPIC "Welcome to the control channel. Type \2help\2 for help information."
+ #define IRCD_INFO PACKAGE " <http://www.bitlbee.org/>"
+-#define MAX_NICK_LENGTH 24
++#define MAX_NICK_LENGTH 99
+ #define HELP_FILE VARDIR "help.txt"
+ #define CONF_FILE_DEF ETCDIR "bitlbee.conf"
+diff --git a/tests/check_nick.c b/tests/check_nick.c
+index ca5e5111..909fdcc9 100644
+--- a/tests/check_nick.c
++++ b/tests/check_nick.c
+@@ -11,16 +11,16 @@
+ START_TEST(test_nick_strip){
+       int i;
+       const char *get[] = { "test:", "test", "test\n",
+-                            "thisisaveryveryveryverylongnick",
+-                            "thisisave:ryveryveryverylongnick",
++                            "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
++                            "thisis:averyveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
+                             "t::::est",
+                             "test123",
+                             "123test",
+                             "123",
+                             NULL };
+       const char *expected[] = { "test", "test", "test",
+-                                 "thisisaveryveryveryveryl",
+-                                 "thisisaveryveryveryveryl",
++                                 "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryve",
++                                 "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryve",
+                                  "test",
+                                  "test123",
+                                  "_123test",
+@@ -28,7 +28,7 @@ START_TEST(test_nick_strip){
+                                  NULL };
+       for (i = 0; get[i]; i++) {
+-              char copy[60];
++              char copy[260];
+               strcpy(copy, get[i]);
+               nick_strip(NULL, copy);
+               fail_unless(strcmp(copy, expected[i]) == 0,
+@@ -53,7 +53,7 @@ END_TEST
+ START_TEST(test_nick_ok_notok)
+ {
+-      const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnick",
++      const char *nicks[] = { "thisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnickthisisaveryveryveryveryveryveryverylongnick",
+                               "\nillegalchar", "", "nick%", "123test", NULL };
+       int i;
diff --git a/overlays/bitlbee/default.nix b/overlays/bitlbee/default.nix
new file mode 100644 (file)
index 0000000..5183d01
--- /dev/null
@@ -0,0 +1,5 @@
+self: super: {
+  bitlbee = super.bitlbee.overrideAttrs(old: {
+    patches = (old.patches or []) ++ [ ./bitlbee_long_nicks.patch ];
+  });
+}
diff --git a/overlays/bundix/default.nix b/overlays/bundix/default.nix
new file mode 100644 (file)
index 0000000..6c4046c
--- /dev/null
@@ -0,0 +1,7 @@
+self: super: {
+  bundix = super.bundix.overrideAttrs (old: {
+    preBuild = (old.preBuild or "") + ''
+      sed -i -e "/case obj/a\      when nil\n        nil" lib/bundix/nixer.rb
+      '';
+  });
+}
diff --git a/overlays/databases/mysql/default.nix b/overlays/databases/mysql/default.nix
new file mode 100644 (file)
index 0000000..5e40284
--- /dev/null
@@ -0,0 +1,12 @@
+self: super: rec {
+  mariadb = mariadbPAM;
+  mariadbPAM = super.mariadb.overrideAttrs(old: {
+    cmakeFlags = old.cmakeFlags ++ [ "-DWITH_AUTHENTICATION_PAM=ON" ];
+    buildInputs = old.buildInputs ++ [ self.pam ];
+  }) // (with super.mariadb; {
+    inherit client;
+    servier = super.mariadb;
+    inherit connector-c;
+    inherit galera;
+  });
+}
diff --git a/overlays/databases/postgresql/default.nix b/overlays/databases/postgresql/default.nix
new file mode 100644 (file)
index 0000000..8d1405e
--- /dev/null
@@ -0,0 +1,11 @@
+self: super: rec {
+  postgresql_11_custom = super.postgresql_11.overrideAttrs(old: {
+    # datadir in /var/lib/postgresql is named after psqlSchema
+    passthru = old.passthru // { psqlSchema = "11.0"; };
+    configureFlags = old.configureFlags ++ [ "--with-pam" ];
+    buildInputs = (old.buildInputs or []) ++ [ self.pam ];
+    patches = old.patches ++ [
+      ./postgresql_run_socket_path.patch
+    ];
+  });
+}
diff --git a/overlays/databases/postgresql/postgresql_run_socket_path.patch b/overlays/databases/postgresql/postgresql_run_socket_path.patch
new file mode 100644 (file)
index 0000000..b558c7b
--- /dev/null
@@ -0,0 +1,12 @@
+diff -Naur postgresql-9.2.0.sockets/src/include/pg_config_manual.h postgresql-9.2.0/src/include/pg_config_manual.h
+--- postgresql-9.2.0.sockets/src/include/pg_config_manual.h    2012-09-06 17:26:17.000000000 -0400
++++ postgresql-9.2.0/src/include/pg_config_manual.h    2012-09-06 18:13:18.183092471 -0400
+@@ -144,7 +144,7 @@
+  * here's where to twiddle it.  You can also override this at runtime
+  * with the postmaster's -k switch.
+  */
+-#define DEFAULT_PGSOCKET_DIR  "/tmp"
++#define DEFAULT_PGSOCKET_DIR  "/run/postgresql"
+ /*
+  * The random() function is expected to yield values between 0 and
diff --git a/overlays/default.nix b/overlays/default.nix
new file mode 100644 (file)
index 0000000..408515e
--- /dev/null
@@ -0,0 +1,31 @@
+{
+  mylibs = self: super: { mylibs = import ../libs.nix { pkgs = self; }; };
+  mypkgs = self: super: import ../pkgs { pkgs = self; };
+
+  bitlbee = import ./bitlbee;
+  bundix = import ./bundix;
+  dwm = import ./dwm;
+  elinks = import ./elinks;
+  gitweb = import ./gitweb;
+  goaccess = import ./goaccess;
+  kanboard = import ./kanboard;
+  ldapvi = import ./ldapvi;
+  lesspipe = import ./lesspipe;
+  mysql = import ./databases/mysql;
+  neomutt = import ./neomutt;
+  nixops = import ./nixops;
+  pass = import ./pass;
+  pelican = import ./pelican;
+  postgresql = import ./databases/postgresql;
+  profanity = import ./profanity;
+  sc-im = import ./sc-im;
+  shaarli = import ./shaarli;
+  slrn = import ./slrn;
+  taskwarrior = import ./taskwarrior;
+  vit = import ./vit;
+  weboob = import ./weboob;
+  weechat = import ./weechat;
+  ympd = import ./ympd;
+}
+// import ./python-packages
+// import ./environments
diff --git a/overlays/dwm/default.nix b/overlays/dwm/default.nix
new file mode 100644 (file)
index 0000000..96ed3ff
--- /dev/null
@@ -0,0 +1,7 @@
+self: super: {
+  dwm = super.dwm.overrideAttrs(old: rec {
+    postPatch = ''
+      cp ${./dwm_config.h} ./config.h
+      '';
+  });
+}
diff --git a/overlays/dwm/dwm_config.h b/overlays/dwm/dwm_config.h
new file mode 100644 (file)
index 0000000..b1587e8
--- /dev/null
@@ -0,0 +1,98 @@
+/* See LICENSE file for copyright and license details. */
+
+/* appearance */
+static const unsigned int borderpx  = 1;        /* border pixel of windows */
+static const unsigned int snap      = 32;       /* snap pixel */
+static const int showbar            = 1;        /* 0 means no bar */
+static const int topbar             = 1;        /* 0 means bottom bar */
+static const char *fonts[]          = { "monospace:size=10" };
+static const char dmenufont[]       = "monospace:size=10";
+static const char col_gray1[]       = "#222222";
+static const char col_gray2[]       = "#444444";
+static const char col_gray3[]       = "#bbbbbb";
+static const char col_gray4[]       = "#eeeeee";
+static const char col_cyan[]        = "#005577";
+static const char *colors[][3]      = {
+       /*               fg         bg         border   */
+       [SchemeNorm] = { col_gray3, col_gray1, col_gray2 },
+       [SchemeSel]  = { col_gray4, col_cyan,  col_cyan  },
+};
+
+/* tagging */
+static const char *tags[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9" };
+
+static const Rule rules[] = {
+       /* xprop(1):
+        *      WM_CLASS(STRING) = instance, class
+        *      WM_NAME(STRING) = title
+        */
+       /* class       instance    title      tags mask     isfloating   monitor */
+       { "Nextcloud", NULL,       NULL,      9 << 8,       0,           -1 },
+};
+
+/* layout(s) */
+static const float mfact     = 0.55; /* factor of master area size [0.05..0.95] */
+static const int nmaster     = 1;    /* number of clients in master area */
+static const int resizehints = 1;    /* 1 means respect size hints in tiled resizals */
+
+static const Layout layouts[] = {
+       /* symbol     arrange function */
+       { "[M]",      monocle }, /* first entry is default */
+       { "[]=",      tile },
+       { "><>",      NULL },    /* no layout function means floating behavior */
+};
+
+/* key definitions */
+#define MODKEY Mod1Mask
+#define TAGKEYS(KEY,TAG) \
+       { MODKEY,                       KEY,      view,           {.ui = 1 << TAG} }, \
+       { MODKEY|ControlMask,           KEY,      toggleview,     {.ui = 1 << TAG} }, \
+       { MODKEY|ShiftMask,             KEY,      tag,            {.ui = 1 << TAG} }, \
+       { MODKEY|ControlMask|ShiftMask, KEY,      toggletag,      {.ui = 1 << TAG} },
+
+/* helper for spawning shell commands in the pre dwm-5.0 fashion */
+#define SHCMD(cmd) { .v = (const char*[]){ "/bin/sh", "-c", cmd, NULL } }
+
+/* commands */
+static char dmenumon[2] = "0"; /* component of dmenucmd, manipulated in spawn() */
+static const char *dmenucmd[] = { "dmenu_run", "-m", dmenumon, "-fn", dmenufont, "-nb", col_gray1, "-nf", col_gray3, "-sb", col_cyan, "-sf", col_gray4, NULL };
+static const char *termcmd[]  = { "st", NULL };
+
+static Key keys[] = {
+       /* modifier                     key        function        argument */
+       { MODKEY,                       XK_p,      spawn,          {.v = dmenucmd } },
+       { MODKEY,                       XK_t,      spawn,          {.v = termcmd } },
+       { MODKEY,                       XK_Tab,    view,           {0} },
+       { MODKEY|ShiftMask,             XK_c,      killclient,     {0} },
+       { MODKEY,                       XK_j,      focusstack,     {.i = +1 } },
+       { MODKEY,                       XK_k,      focusstack,     {.i = -1 } },
+       { MODKEY,                       XK_Return, zoom,           {0} },
+       TAGKEYS(                        XK_1,                      0)
+       TAGKEYS(                        XK_2,                      1)
+       TAGKEYS(                        XK_3,                      2)
+       TAGKEYS(                        XK_4,                      3)
+       TAGKEYS(                        XK_5,                      4)
+       TAGKEYS(                        XK_6,                      5)
+       TAGKEYS(                        XK_7,                      6)
+       TAGKEYS(                        XK_8,                      7)
+       TAGKEYS(                        XK_9,                      8)
+       { MODKEY|ShiftMask,             XK_q,      quit,           {0} },
+};
+
+/* button definitions */
+/* click can be ClkTagBar, ClkLtSymbol, ClkStatusText, ClkWinTitle, ClkClientWin, or ClkRootWin */
+static Button buttons[] = {
+       /* click                event mask      button          function        argument */
+       { ClkLtSymbol,          0,              Button1,        setlayout,      {0} },
+       { ClkLtSymbol,          0,              Button3,        setlayout,      {.v = &layouts[2]} },
+       { ClkWinTitle,          0,              Button2,        zoom,           {0} },
+       { ClkStatusText,        0,              Button2,        spawn,          {.v = termcmd } },
+       { ClkClientWin,         MODKEY,         Button1,        movemouse,      {0} },
+       { ClkClientWin,         MODKEY,         Button2,        togglefloating, {0} },
+       { ClkClientWin,         MODKEY,         Button3,        resizemouse,    {0} },
+       { ClkTagBar,            0,              Button1,        view,           {0} },
+       { ClkTagBar,            0,              Button3,        toggleview,     {0} },
+       { ClkTagBar,            MODKEY,         Button1,        tag,            {0} },
+       { ClkTagBar,            MODKEY,         Button3,        toggletag,      {0} },
+};
+
diff --git a/overlays/elinks/default.nix b/overlays/elinks/default.nix
new file mode 100644 (file)
index 0000000..1744dc0
--- /dev/null
@@ -0,0 +1,14 @@
+self: super: {
+  elinks = super.elinks.overrideAttrs (old:
+    self.mylibs.fetchedGithub ./elinks.json // rec {
+      preConfigure = ''sh autogen.sh'';
+      buildInputs = old.buildInputs ++ (with self; [ gettext automake autoconf ]);
+      configureFlags = [
+        "--disable-smb" "--without-x" "--enable-cgi"
+        "--enable-leds" "--enable-256-colors"
+        "--enable-html-highlight" "--with-zlib"
+        ];
+      patches = [];
+    }
+  );
+}
diff --git a/overlays/elinks/elinks.json b/overlays/elinks/elinks.json
new file mode 100644 (file)
index 0000000..ea13b1f
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "f86be65-master",
+  "meta": {
+    "name": "elinks",
+    "url": "https://github.com/nabetaro/elinks",
+    "branch": "master"
+  },
+  "github": {
+    "owner": "nabetaro",
+    "repo": "elinks",
+    "rev": "f86be659718c0cd0a67f88b42f07044c23d0d028",
+    "sha256": "1jxb7xgawcjkb3gw4gqyw26g02709wwdbhyczfckh3l4njxhy14m",
+    "fetchSubmodules": true
+  }
+}
diff --git a/overlays/environments/default.nix b/overlays/environments/default.nix
new file mode 100644 (file)
index 0000000..630b0bd
--- /dev/null
@@ -0,0 +1,3 @@
+{
+  immae-eu = import ./immae-eu.nix;
+}
diff --git a/overlays/environments/immae-eu.nix b/overlays/environments/immae-eu.nix
new file mode 100644 (file)
index 0000000..1f27e7c
--- /dev/null
@@ -0,0 +1,116 @@
+self: super: with self;
+let
+  # https://github.com/NixOS/nixpkgs/blob/master/pkgs/stdenv/generic/setup.sh
+  # https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks
+  paths = [
+    # archives
+    lzo unzip bzip2 p7zip xz
+    # unrar is unfree
+
+    # backups
+    duply
+
+    # calendar/contacts
+    abook khard khal cadaver vdirsyncer pal
+
+    # computing
+    boinctui
+
+    # cryptocurrencies
+    cardano sia monero
+    xmr-stak
+    solc
+    iota-cli-app
+
+    # debugging
+    rr valgrind netcat-gnu strace
+
+    # documentations
+    unicodeDoc
+
+    # e-mails
+    muttprint mutt-ics
+    notmuch-python2 notmuch-python3 notmuch-vim
+    neomutt mairix notmuch
+    bogofilter fetchmail
+
+    # git
+    vcsh gitRepo gitAndTools.stgit tig
+
+    # graphical tools
+    nextcloud-client firefox
+    dwm dmenu st
+
+    # images
+    feh imagemagick tiv graphicsmagick
+
+    # internet browsing
+    w3m lynx links elinks browsh weboob urlview googler urlwatch
+
+    # less
+    python3Packages.pygments lesspipe highlight sourceHighlight
+
+    # monitoring
+    cnagios mtop pg_activity nagios-cli mtr
+    iftop htop iotop iperf
+    goaccess
+    # nagnu
+
+    # messaging/forums/news
+    flrn slrn
+    telegram-cli telegram-history-dump telegramircd
+    weechat profanity
+    newsboat irssi
+
+    # nix
+    mylibs.yarn2nixPackage.yarn2nix
+    nixops nix-prefetch-scripts nix-generate-from-cpan
+    nix-zsh-completions bundix nodePackages.bower2nix
+    nodePackages.node2nix
+    # (nixos {}).nixos-generate-config
+    # (nixos {}).nixos-install
+    # (nixos {}).nixos-enter
+    # (nixos {}).manual.manpages
+
+    # note taking
+    note terminal-velocity jrnl
+
+    # office
+    sc-im ranger
+    genius bc
+    ledger
+    tmux
+    rtorrent
+    ldapvi
+
+    # password management
+    pass apg pwgen
+
+    # pdf
+    pdftk poppler_utils
+
+    # programming
+    pelican emacs26-nox ctags
+    wdiff
+
+    # security
+    keybase
+
+    # todolist/time management
+    taskwarrior vit timewarrior
+
+    # video/music
+    youtube-dl ncmpc ncmpcpp ffmpeg
+
+    # other tools
+    pgloader s3cmd lftp jq cpulimit libxslt
+  ];
+in
+{
+  myEnvironments.immae-eu = buildEnv {
+    name = "immae-eu-packages";
+    inherit paths;
+    pathsToLink = [ "/bin" "/etc" "/include" "/lib" "/libexec" "/share"];
+    extraOutputsToInstall = [ "bin" "man" "doc" "info" ];
+  };
+}
diff --git a/overlays/gitweb/default.nix b/overlays/gitweb/default.nix
new file mode 100644 (file)
index 0000000..aa17d22
--- /dev/null
@@ -0,0 +1,7 @@
+self: super: {
+  gitweb = super.gitweb.overrideAttrs(old: {
+    installPhase = old.installPhase + ''
+      cp -r ${./theme} $out/gitweb-theme;
+      '';
+  });
+}
diff --git a/overlays/gitweb/theme/git-favicon.png b/overlays/gitweb/theme/git-favicon.png
new file mode 100644 (file)
index 0000000..4fa44bb
Binary files /dev/null and b/overlays/gitweb/theme/git-favicon.png differ
diff --git a/overlays/gitweb/theme/git-logo.png b/overlays/gitweb/theme/git-logo.png
new file mode 100644 (file)
index 0000000..fdaf7b7
Binary files /dev/null and b/overlays/gitweb/theme/git-logo.png differ
diff --git a/overlays/gitweb/theme/gitweb.css b/overlays/gitweb/theme/gitweb.css
new file mode 100644 (file)
index 0000000..83e0742
--- /dev/null
@@ -0,0 +1,783 @@
+/* Reset
+------------------------------------------------------------------------- */
+
+/* Based on http://meyerweb.com/eric/tools/css/reset/ */
+/* v1.0 | 20080212 */
+
+html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p,
+blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em,
+font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b,
+u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table,
+caption, tbody, tfoot, thead, tr, th, td {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  outline: 0;
+  font-size: 100%;
+  vertical-align: baseline;
+  background: transparent;
+}
+
+ol, ul { list-style: none; }
+
+blockquote, q { quotes: none; }
+
+blockquote:before, blockquote:after,
+q:before, q:after {
+  content: '';
+  content: none;
+}
+
+:focus { outline: 0; }
+
+ins { text-decoration: none; }
+
+del { text-decoration: line-through; }
+
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+a { outline: none; }
+
+/* General
+---------------------------------------------------------------------------- */
+
+html {
+  position: relative;
+  min-height: 100%;
+}
+
+body {
+  font: 13px Helvetica,arial,freesans,clean,sans-serif;
+  line-height: 1.4;
+  margin: 0 0 105px;
+  background-color: #fff;
+  color: #000000;
+}
+
+/* Monospaced Fonts */
+.sha1, .mode, .diff_tree .list, .pre, .diff, .patchset {
+  font-family: 'Consolas','Bitstream Vera Sans Mono',monospace;
+}
+
+a:link, a:visited {
+  color: #4183C4;
+  text-decoration: none;
+}
+
+a:hover {
+  text-decoration: underline;
+}
+
+td.list a[href*='tree'], td.list a[href*='blob'] {
+  padding-left: 20px;
+  display: block;
+  float: left;
+  height: 16px;
+  line-height: 16px;
+}
+
+td.list a[href*='tree'] {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABq0lEQVQ4y8WTu4oUQRSGv+rtGVuxhwVFdFEEE2c3d0HYTEMTn8DEVxADQTDUF9DMwMxQMBMx8AEWzRQ3cBHd9TI91+2urjq/QbczY2IygSep4nD+79yqnCRWsYQVbWVACvDh5ZXdrLe15dwyT1TjT/sxFFeB6i+VA2B6+cb7kAI4Jf0LO087zjlQI8Y5Qvnj0sHug321XoC1bk+K9eHk6+s7wPMUgKAS88eqb4+Jfg2SHs7lZBvX2Nh+2EUCDGSAcMnJsx9f7NxfAGqXyDzRd5EJO/pMPT1gcviGTnYOVIN5pAAE8v7dLrKL8xnglFk4ws9Afko9HpH3b5Gd2mwb/lOBmgrSdYhJugDUCenxM6xv3p4HCsP8F0LxCsUhCkMURihOyM7fg0osASTFEpu9a4LjGIUCqwcoDiEUrX+E4hRUQb20RiokC1j9vckUhygU7X3QZh7NAVKYL7YBeMkRUfjVCotF2XGIwnghtrJpMywB5G0QZj9P1JNujuWJ1AHLQadRrACPkuZ0SSSWpeStWgDK6tHek5vbiOs48n++XQHurcf0rFng//6NvwG+iB9/4duaTgAAAABJRU5ErkJgggo=) center left no-repeat;
+}
+
+td.list a[href*='blob'] {
+  background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAQAAAC1+jfqAAAA6ElEQVQoFQXBMW5TQRgGwNnHnoE0QbiCjoIooUmTU3AuS1BwIoTSUdJBigg3GCWOg9/++zHTop078wIAsPMrE4SL5/1aIyMjIyMjz/m0tbFECFdrPeaQQw75mz/5nZH7fN7aWILmauSYfznmmIfss8vIUx7zZWsTTXM5vpWvTk5Wq9VHQP/gtgOLa0Qpw940vAQdaG6thpOhlOkG0AEuAVGmEkAH+G4YSikxXQM6wDsAMRFAB/ihDNNUmN4DOsAbBAEAdICfpmmaAt4COoj2GgCASbIkZh1NAACznhQt2itnFgAAlF3u/gMDtJXPzQxoswAAAABJRU5ErkJgggo=) center left no-repeat;
+}
+
+i {
+  font-style: normal;
+}
+
+td, th {
+  padding: 5px;
+}
+
+.page_nav br {
+  display: none;
+}
+
+/* Page Header
+---------------------------------------------------------------------------- */
+
+.page_header {
+  height: 50px;
+  line-height: 50px;
+  position: relative;
+  padding: 0 27px;
+  margin-bottom: 20px;
+  font-size: 20px;
+  font-family: Helvetica, Arial, Freesans, Clean, sans-serif;
+  background: #FFFFFF; /* old browsers */
+  background: -moz-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%); /* firefox */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#FFFFFF), color-stop(100%,#F5F5F5)); /* webkit */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#FFFFFF', endColorstr='#F5F5F5',GradientType=0 ); /* ie */
+  background: -o-linear-gradient(top, #FFFFFF 0%, #F5F5F5 100%);
+  border-bottom: 1px solid #dfdfdf;
+}
+
+.page_header a:link, .page_header a:visited {
+  color: #4183C4;
+  text-decoration: none;
+  padding: 3px;
+  font-weight: bold;
+}
+
+.page_header a:hover {
+  font-weight: bold;
+  padding: 3px;
+  text-decoration: underline;
+}
+
+.page_header a:first-child {
+  background: transparent;
+}
+
+.page_header img.logo {
+  position: relative;
+  top: 7px;
+  margin-right: 5px;
+}
+
+/* Page Footer
+---------------------------------------------------------------------------- */
+
+.page_footer {
+  position: absolute;
+  left: 0;
+  bottom: 0;
+  width: 100%;
+  height: 80px;
+  line-height: 80px;
+  margin-top: 15px;
+  background: #f1f1f1;
+  border-top: 2px solid #ddd;
+  border-bottom: 1px solid #ddd;
+}
+
+.page_footer_text {
+  color: #666;
+  display: inline;
+  float: left;
+  margin-left: 25px;
+  width: 80%;
+  overflow: hidden;
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+a.rss_logo {
+  float: right;
+  padding: 3px 1px;
+  width: 35px;
+  line-height: 10px;
+  border: 1px solid;
+  border-color: #fcc7a5 #7d3302 #3e1a01 #ff954e;
+  color: #ffffff;
+  background-color: #ff6600;
+  font-weight: bold;
+  font-family: sans-serif;
+  font-size: 80%;
+  text-align: center;
+  text-decoration: none;
+  margin-top: 30px;
+  margin-left: 5px;
+}
+
+a.rss_logo:hover {
+  background-color: #ee5500;
+}
+
+.rss_logo {
+  margin-right: 25px;
+  background: yellow;
+}
+
+.rss_logo:last-child {
+  margin-right: 5px;
+}
+
+/* Index include
+---------------------------------------------------------------------------- */
+
+.index_include {
+  width: 95%;
+  margin: 0 auto 15px;
+  background: -moz-linear-gradient(center top , #FFFFFF 0%, #F5F5F5 100%) repeat scroll 0 0 transparent;
+  border: 1px solid #DFDFDF;
+  padding: 8px;
+  -webkit-box-sizing: border-box;
+     -moz-box-sizing: border-box;
+          box-sizing: border-box;
+}
+
+/* Elements
+---------------------------------------------------------------------------- */
+
+.project_list,
+.shortlog,
+.tree,
+.commit_search,
+.history {
+  width: 95%;
+  margin: 0 auto 15px auto;
+  border: 1px solid #d8d8d8;
+  -moz-box-shadow: 0 0 3px rgba(0,0,0,0.2);
+  -webkit-box-shadow: 0 0 3px rgba(0,0,0,0.2);
+  box-shadow: 0 0 3px rgba(0,0,0,0.2);
+}
+
+.project_list th,
+.shortlog th,
+.tree th,
+.commit_search th {
+  color: #afafaf;
+  font-weight: normal;
+}
+
+.project_list th {
+  font-weight: bold;
+}
+
+.project_list tr,
+.shortlog tr,
+.tree tr,
+.commit_search tr {
+  background: #eaeaea;
+  height: 2.5em;
+  text-align: left;
+  color: #545454;
+}
+
+.project_list tr.dark, .project_list tr.light,
+.shortlog tr.dark, .shortlog tr.light,
+.tree tr.dark, .tree tr.light,
+.commit_search tr.dark, .commit_search tr.light,
+.history tr.dark, .history tr.light,
+.heads tr.dark, .heads tr.light {
+  background: #F9F9F9; /* old browsers */
+  background: -moz-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%); /* firefox */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#F9F9F9), color-stop(100%,#EFEFEF)); /* webkit */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F9F9F9', endColorstr='#EFEFEF',GradientType=0 ); /* ie */
+  background: -o-linear-gradient(top, #F9F9F9 0%, #EFEFEF 100%);
+  height: 2.5em;
+  border-bottom: 1px solid #e1e1e1;
+}
+
+th .header {
+  background: transparent;
+  border: 0;
+  padding: 0;
+  font-weight: bold;
+}
+
+.tree {
+  width: 100%;
+  margin: 0;
+}
+
+.projsearch {
+  position: absolute;
+  right: 4%;
+  top: 15px;
+}
+
+.projsearch a {
+  display: none;
+}
+
+.commit_search {
+  background: #eaeaea;
+}
+
+.page_nav,
+.list_head,
+.page_path,
+.search {
+  width: 94%;
+  background: #eaeaea;
+  color: #545454;
+  border: 1px solid #d8d8d8;
+  padding: 5px;
+  margin: 0 auto 15px auto;
+}
+
+.history {
+  background: #eaeaea;
+}
+
+.title {
+  margin: 0 auto 15px auto;
+  padding: 5px;
+  width: 95%;
+}
+
+.readme {
+  background: #eaf2f5;
+  border: 1px solid #bedce7;
+  -moz-box-sizing: border-box;
+  -webkit-box-sizing: border-box;
+  box-sizing: border-box;
+  margin: 0 auto 15px auto;
+  padding: 15px;
+  width: 95%;
+}
+
+.readme h1 {
+  display: block;
+  font-size: 2em;
+  font-weight: bold;
+  margin-bottom: 0.67em;
+  margin-top: 0;
+}
+
+.readme h2 {
+  font-size: 1.5em;
+  font-weight: bold;
+  margin-bottom: 0.83em;
+}
+
+
+.readme h3 {
+  font-size: 1.17em;
+  font-weight: bold;
+  margin-bottom: 1em;
+}
+
+.readme p {
+  margin-bottom: 1em;
+}
+
+.readme ul {
+  list-style: disc;
+  margin-bottom: 1em;
+  margin-left: 1.5em;
+}
+
+.readme ul ul {
+  margin-bottom: 0;
+}
+
+.readme ol {
+  list-style: decimal;
+  margin-bottom: 1em;
+  margin-left: 1.5em;
+}
+
+.readme ol ol {
+  margin-bottom: 0;
+}
+
+.readme pre {
+  font-family: monospace;
+  margin: 1em 0;
+  white-space: pre;
+}
+
+.readme tt, .readme code, .readme kbd, .readme samp {
+  font-family: monospace;
+}
+
+.readme blockquote {
+  margin: 1em;
+}
+
+.projects_list,
+.tags {
+  width: 95%;
+  background: #f0f0f0;
+  color: #545454;
+  border: 1px solid #d8d8d8;
+  padding: 5px;
+  margin: 0 auto 15px auto;
+}
+
+.heads {
+  width: 95%;
+  color: #545454;
+  border: 1px solid #d8d8d8;
+  padding: 5px;
+  margin: 0 auto 15px auto;
+}
+
+.header {
+  width: 94%;
+  margin: 0 auto 15px auto;
+  background: #eaf2f5;
+  border: 1px solid #bedce7;
+  padding: 5px;
+}
+
+.header .age {
+  float: left;
+  color: #000;
+  font-weight: bold;
+  width: 10em;
+}
+
+.title_text {
+  width: 94%;
+  background: #eaf2f5;
+  border: 1px solid #bedce7;
+  padding: 5px;
+  margin: 0 auto 0 auto;
+}
+
+.log_body {
+  width: 94%;
+  background: #eaf2f5;
+  border: 1px solid #bedce7;
+  border-top: 0;
+  padding: 5px;
+  margin: 0 auto 15px auto;
+}
+
+.page_body {
+  line-height: 1.4em;
+  width: 94%;
+  background: #f8f8f8;
+  border: 1px solid #d8d8d8;
+  padding: 5px;
+  margin: 15px auto 15px auto;
+}
+
+.diff_tree {
+  width: 95%;
+  background: #f0f0f0;
+  border: 1px solid #d8d8d8;
+  padding: 5px;
+  margin: 0 auto 15px auto;
+}
+
+.page_body > .list_head {
+  width: 98.5%;
+}
+
+.page_body > .diff_tree {
+  width: 99.5%;
+}
+
+.patch > .header {
+  width: 99%;
+}
+
+.author .avatar,
+.author_date .avatar {
+  position: relative;
+  top: 3px;
+}
+
+.object_header .avatar {
+  border: 1px solid #D8D8D8;
+  float: right;
+}
+
+.object_header td,
+.object_header th {
+  vertical-align: top;
+}
+
+/* Refs
+---------------------------------------------------------------------------- */
+
+span.refs span {
+  color: #707070;
+  display: inline-block;
+  margin: 0;
+  background-color: #eee;
+  border: 1px solid #ccc;
+  border-radius: 3px;
+  height: 18px;
+  padding: 0 6px;
+  text-overflow: ellipsis;
+}
+
+span.refs span.ref {
+  color: #707070;
+  display: inline-block;
+  margin: 0;
+  background-color: #c4c4ff;
+  border: 1px solid #7878ff;
+  border-radius: 3px;
+  height: 18px;
+  padding: 0 6px;
+  text-overflow: ellipsis;
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUnpolg7AAAAHJQTFRFAAAAVVWqZmbMVVXVYGDgbW3td3fuc3PzdHT0cHD1d3f6dHT6dnb7dHT7dnb8dnb8dnb9d3f9dnb+eHj+d3f+eHj+d3f+d3f+d3f+eHj+d3f+eHj+d3f+eHj+d3f+d3f+eHj+d3f+d3f+d3f+eHj/////V9oQhQAAACR0Uk5TAAIEBQcNDhMVGCotNTZAT217i5CgobvExtjZ4eLr7vP09ff7uqQ6cgAAAAFiS0dEJcMByQ8AAABUSURBVBjTpc43AoAwDENRh95bgNBM1f3PyOpslD++RSJ61YgH5M2IbIkn4GocSR1MZVBL4t2n4FgkbaxI8Sqph041WknZCWAIrcmEUbpf3lNe0N9u59YFYHnZ78gAAAAASUVORK5CYII=);
+  background-repeat: no-repeat;
+  padding-left: 18px;
+}
+
+span.refs span.tag {
+  color: #707070;
+  display: inline-block;
+  margin: 0;
+  background-color: #ffffab;
+  border: 1px solid #d9d93b;
+  border-radius: 3px;
+  height: 18px;
+  padding: 0 6px;
+  text-overflow: ellipsis;
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAMAAABhEH5lAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSUZZ+h9RwAAAGZQTFRFAAAAtrYkwMBAwMBAx8c4yso11NQ71NQ51dU52Ng71tY519c719c719c62Ng719c719c62Ng72dk62Ng62Ng72Ng72dk62Ng72Ng62dk62dk72dk62Ng62dk72Ng72Ng72dk7////ou/AnQAAACB0Uk5TAAYHCxESLjRCWWlqa4uNkpissbrO19jc3ufs8vf6/f7atAU2AAAAAWJLR0QhxGwNFgAAAF1JREFUGFeNy0cOgCAABVGw94rY5d//lC7omhhn+ZIh5Gf1xPk0Zi5dAABROIQjSU/fsAXhDkCUljAv8jW2wlQpaixpo4Nj+dtatVpjkSJjLNaizRVpvhBCu/4h391jzw1lU12Z7wAAAABJRU5ErkJggg==);
+  background-repeat: no-repeat;
+  padding-left: 18px;
+}
+
+span.refs span.head {
+  color: #707070;
+  display: inline-block;
+  margin: 0;
+  background-color: #c4ffc4;
+  border: 1px solid #78ff78;
+  border-radius: 3px;
+  height: 18px;
+  padding: 0 6px;
+  text-overflow: ellipsis;
+  background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3gIKFSYDsafX/gAAAUpJREFUOMvVkjFLA0EQhd/s7l06MSCihbV/wC5/QBDEIFYWprRIIQQJFqKFQi4kUbBQsFSwtrUQLQULUTBFLCzVIgimCXe7z0q5yIWcqfRVwzDzMTNvgL8mSUqWw3JOtFQJdsIwLDYyjdYgkEmkazl2oVtQWk36nn8AYBYASmFpxmizGtnoqO7Vb+M9KglEkASdpWU872nvVCiPRpuTnz2JIHGyqX3d0kZfR1G0Ht+g/do+FIhOBbLW3n/FNb/28D0puZ+dyL44ur1UoH5yzt2JyIj6UGdDgwrPhYzSagNEszJaeU/lWlylbmnaeGZZICsAppxzi6nt73HK85oQCMknOuarpno+FIjglVjZDXaCS2yDv3rIHlCb88FY0BlUl3hs7ektkhckb5DFWhoz+n12zr7ZPLpYUqLm0oBMn8NUzLhpAgjpWMS/1CcSJ3ykD7Rk1QAAAABJRU5ErkJggg==);
+  background-repeat: no-repeat;
+  padding-left: 18px;
+}
+
+span.refs a {
+  color: #4e4e4e;
+  font: 11px "Bitstream Vera Sans Mono", "DejaVu Sans Mono", Monaco, monospace;
+  line-height: 18px;
+}
+
+/* Diffs
+---------------------------------------------------------------------------- */
+
+div.diff.to_file a.path,
+div.diff.to_file {
+  color: #007000;
+}
+
+div.diff.from_file a.path,
+div.diff.from_file {
+  color: #aa0000;
+}
+
+.patch .header {
+  margin: 0;
+}
+
+.patchset {
+  overflow-x: auto;
+  overflow-y: hidden;
+}
+
+.chunk_header {
+  background: #eaf2f5;
+  color: #999;
+}
+
+.rem {
+  background: #ffdddd;
+}
+.rem .marked {
+  background: #ffaaaa;
+}
+.add {
+  background: #ddffdd;
+}
+.add .marked {
+  background: #7dff7d;
+}
+
+.extended_header {
+  width: 99.5%;
+}
+
+div.chunk_block {
+  overflow: hidden;
+}
+
+div.chunk_block div.old {
+  float: left;
+  width: 50%;
+  overflow: hidden;
+  border-right: 5px solid #EAF2F5;
+}
+
+div.chunk_block.rem,
+div.chunk_block.add {
+  background: transparent;
+}
+
+div.chunk_block div.old .add,
+div.chunk_block div.old .rem {
+  padding-right: 3px;
+}
+
+div.chunk_block div.new .add,
+div.chunk_block div.new .rem {
+  padding-left: 3px;
+}
+
+div.chunk_block div.new {
+  margin-left: 50%;
+  width: 50%;
+  border-left: 5px solid #EAF2F5;
+}
+
+/* Category
+---------------------------------------------------------------------------- */
+
+td.category {
+  background: #E6F1F6; /* old browsers */
+  background: -moz-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%); /* firefox */
+  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#C8D8E7), color-stop(100%,#E6F1F3)); /* webkit */
+  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#C8D8E7', endColorstr='#E6F1F3',GradientType=0 ); /* ie */
+  background: -o-linear-gradient(top, #C8D8E7 0%, #E6F1F3 100%);
+  font-weight: bold;
+  border-bottom: 1px solid #D1D1D1;
+  border-top: 1px solid #D1D1D1;
+}
+
+/* Age
+---------------------------------------------------------------------------- */
+
+/* noage: "No commits" */
+.project_list td.noage {
+  color: #cdcdcd;
+}
+
+/* age2: 60*60*24*2 <= age */
+.project_list td.age2, .blame td.age2 {
+  color: #545454;
+}
+
+/* age1: 60*60*2 <= age < 60*60*24*2 */
+.project_list td.age1 {
+  color: #009900;
+}
+
+/* age0: age < 60*60*2 */
+.project_list td.age0 {
+  color: #009900;
+  font-weight: bold;
+}
+
+/* File status
+---------------------------------------------------------------------------- */
+
+.diff_tree span.file_status.new {
+  color: #008000;
+}
+
+table.diff_tree span.file_status.deleted {
+  color: #c00000;
+}
+
+table.diff_tree span.file_status.moved,
+table.diff_tree span.file_status.mode_chnge {
+  color: #545454;
+}
+
+table.diff_tree span.file_status.copied {
+  color: #70a070;
+}
+
+span.cntrl {
+  border: dashed #aaaaaa;
+  border-width: 1px;
+  padding: 0px 2px 0px 2px;
+  margin:  0px 2px 0px 2px;
+}
+
+span.match {
+  background: #aaffaa;
+  color: #000;
+}
+
+td.error {
+  color: red;
+  background: yellow;
+}
+
+/* blob view */
+
+td.pre, div.pre, div.diff {
+  white-space: pre-wrap;
+}
+
+/* JavaScript-based timezone manipulation */
+
+.popup { /* timezone selection UI */
+       position: absolute;
+       /* "top: 0; right: 0;" would be better, if not for bugs in browsers */
+       top: 0; left: 0;
+       border: 1px solid #d8d8d8;
+       padding: 2px;
+       background-color: #f0f0f0;
+       font-style: normal;
+       color: #545454;
+       cursor: auto;
+}
+
+.close-button { /* close timezone selection UI without selecting */
+       /* float doesn't work within absolutely positioned container,
+        * if width of container is not set explicitly */
+       /* float: right; */
+       position: absolute;
+       top: 0px; right: 0px;
+       border:  1px solid #ffaaaa;
+       margin:  1px 1px 1px 1px;
+       padding-bottom: 2px;
+       width:     12px;
+       height:    10px;
+       font-size:  9px;
+       font-weight: bold;
+       text-align: center;
+       background-color: #ffdddd;
+       cursor: pointer;
+}
+
+/* Style definition generated by highlight 2.4.5, http://www.andre-simon.de/ */
+
+/* Highlighting theme definition: */
+
+.num    { color:#6ecf36; }
+.esc    { color:#ff00ff; }
+.str    { color:#ff00d3; background-color: #edc9ec }
+.dstr   { color:#818100; }
+.slc    { color:#838183; font-style:italic; }
+.com    { color:#838183; font-style:italic; }
+.dir    { color:#008200; }
+.sym    { color:#000000; }
+.line   { color:#555555; }
+.kwa    { color:#666666; font-weight:bold; }
+.kwb    { color:#6b3099; }
+.kwc    { color:#d4663d; }
+.kwd    { color:#2928ff; }
+
+/**** Styles supplémentaires *****/
+
+.readme div.toc {
+  float: right;
+  border: 1px solid black;
+  background-color: white;
+}
+.readme div.toc span.toctitle {
+  display: inline-block;
+  width: 100%;
+  text-align: center;
+  font-weight: bold;
+}
+
+.readme table {
+  background-color: white;
+}
+
+.readme table thead tr {
+  background-color: #ccc;
+}
+
+.readme table tbody tr:nth-child(2n) {
+  background-color: #f8f8f8;
+}
+
+.readme table td, .readme table th {
+  border: 1px solid black;
+}
diff --git a/overlays/gitweb/theme/gitweb.js b/overlays/gitweb/theme/gitweb.js
new file mode 100644 (file)
index 0000000..72f3cfa
--- /dev/null
@@ -0,0 +1,27 @@
+function include(filename, onload) {
+  var head   = document.getElementsByTagName('head')[0];
+  var script = document.createElement('script');
+  script.src = filename;
+  script.type = 'text/javascript';
+  script.onload = script.onreadystatechange = function() {
+    if (script.readyState) {
+      if (script.readyState === 'complete' || script.readyState === 'loaded') {
+        script.onreadystatechange = null;
+        onload();
+      }
+    } 
+    else {
+      onload();
+    }
+  }
+  head.appendChild(script);
+}
+
+include('static/gitweb.js', function() {});
+include('//code.jquery.com/jquery-3.1.0.min.js', function() {
+  $("div.title").each(function(index, element) {
+    if ($(element).text() === "readme" || $(element).text() === " ") {
+      $(element).hide();
+    }
+  });
+});
diff --git a/overlays/goaccess/default.nix b/overlays/goaccess/default.nix
new file mode 100644 (file)
index 0000000..12b28f3
--- /dev/null
@@ -0,0 +1,13 @@
+self: super: {
+  goaccess = super.goaccess.overrideAttrs(old: rec {
+    name = "goaccess-${version}";
+    version = "1.3";
+    src = self.fetchurl {
+      url = "https://tar.goaccess.io/${name}.tar.gz";
+      sha256 = "16vv3pj7pbraq173wlxa89jjsd279004j4kgzlrsk1dz4if5qxwc";
+    };
+    configureFlags = old.configureFlags ++ [ "--enable-tcb=btree" ];
+    buildInputs = old.buildInputs ++ [ self.tokyocabinet self.bzip2 ];
+  });
+
+}
diff --git a/overlays/kanboard/default.nix b/overlays/kanboard/default.nix
new file mode 100644 (file)
index 0000000..81b39fe
--- /dev/null
@@ -0,0 +1,18 @@
+self: super: {
+  kanboard = { kanboard_config ? "/etc/kanboard/config.php" }:
+    super.kanboard.overrideAttrs(old: rec {
+      name = "kanboard-${version}";
+      version = "1.2.9";
+      src = self.fetchFromGitHub {
+        owner = "kanboard";
+        repo = "kanboard";
+        rev = "c4152316b14936556edf3bcc4d11f16ba31b8ae7";
+        sha256 = "18bn9zhyfc5x28hwcxss7chdq7c8rshc8jxgai65i5l68iwhvjg7";
+      };
+      installPhase = ''
+        cp -a . $out
+        ln -s ${kanboard_config} $out/config.php
+        mv $out/data $out/dataold
+        '';
+    });
+}
diff --git a/overlays/ldapvi/default.nix b/overlays/ldapvi/default.nix
new file mode 100644 (file)
index 0000000..030e676
--- /dev/null
@@ -0,0 +1,3 @@
+self: super: {
+  ldapvi = super.ldapvi.overrideAttrs (old: self.mylibs.fetchedGit ./ldapvi.json);
+}
diff --git a/overlays/ldapvi/ldapvi.json b/overlays/ldapvi/ldapvi.json
new file mode 100644 (file)
index 0000000..ceaff71
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "tag": "f1d42ba-master",
+  "meta": {
+    "name": "ldapvi",
+    "url": "http://www.lichteblau.com/git/ldapvi.git",
+    "branch": "master"
+  },
+  "git": {
+    "url": "http://www.lichteblau.com/git/ldapvi.git",
+    "rev": "f1d42bad66cc4623d1ff21fbd5dddbf5009d3e40",
+    "sha256": "0c2h4b1spp9z6a16gy9azf0wyxq397yy7001x1zlvc7c60q11wry",
+    "fetchSubmodules": true
+  }
+}
diff --git a/overlays/lesspipe/default.nix b/overlays/lesspipe/default.nix
new file mode 100644 (file)
index 0000000..e53feae
--- /dev/null
@@ -0,0 +1,5 @@
+self: super: {
+  lesspipe = super.lesspipe.overrideAttrs(old: {
+    configureFlags = (old.configureFlags or []) ++ [ "--yes" ];
+  });
+}
diff --git a/overlays/neomutt/default.nix b/overlays/neomutt/default.nix
new file mode 100644 (file)
index 0000000..c8578c9
--- /dev/null
@@ -0,0 +1,8 @@
+self: super: {
+  neomutt = super.neomutt.overrideAttrs (old:
+    {
+      buildInputs = old.buildInputs ++ [ self.gdbm ];
+      configureFlags = old.configureFlags ++ [ "--gdbm" ];
+    }
+  );
+}
diff --git a/overlays/nixops/default.nix b/overlays/nixops/default.nix
new file mode 100644 (file)
index 0000000..eb29ecd
--- /dev/null
@@ -0,0 +1,7 @@
+self: super: {
+  nixops = super.nixops.overrideAttrs (old: {
+    preConfigure = (old.preConfigure or "") + ''
+      sed -i -e "/'keyFile'/s/'path'/'string'/" nixops/backends/__init__.py
+      '';
+  });
+}
diff --git a/overlays/pass/default.nix b/overlays/pass/default.nix
new file mode 100644 (file)
index 0000000..df42cf1
--- /dev/null
@@ -0,0 +1,8 @@
+self: super: {
+  pass = (super.pass.withExtensions (exts: [ exts.pass-otp ])).overrideAttrs (old:
+    self.mylibs.fetchedGit ./pass.json // {
+      patches = old.patches ++ [ ./pass-fix-pass-init.patch ];
+    }
+  );
+
+}
diff --git a/overlays/pass/pass-fix-pass-init.patch b/overlays/pass/pass-fix-pass-init.patch
new file mode 100644 (file)
index 0000000..10a76c1
--- /dev/null
@@ -0,0 +1,42 @@
+From 33e8f1cd0065639a948d7b5ba3f93d43bdf7f3be Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= <ismael.bouya@normalesup.org>
+Date: Sun, 11 Nov 2018 19:47:33 +0100
+Subject: [PATCH] Fix pass init for some gpg keys
+
+This fixes the pass init for gpg keys which have their main key as
+encryption key. This may happen for instance with RSA keys and specific
+configuration.
+---
+ src/password-store.sh       | 2 +-
+ tests/t0300-reencryption.sh | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/password-store.sh b/src/password-store.sh
+index d89d455..44d122e 100755
+--- a/src/password-store.sh
++++ b/src/password-store.sh
+@@ -124,7 +124,7 @@ reencrypt_path() {
+                               IFS=";" eval 'GPG_RECIPIENTS+=( $group )' # http://unix.stackexchange.com/a/92190
+                               unset "GPG_RECIPIENTS[$index]"
+                       done
+-                      gpg_keys="$($GPG $PASSWORD_STORE_GPG_OPTS --list-keys --with-colons "${GPG_RECIPIENTS[@]}" | sed -n 's/^sub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u)"
++                      gpg_keys="$($GPG $PASSWORD_STORE_GPG_OPTS --list-keys --with-colons "${GPG_RECIPIENTS[@]}" | sed -n 's/^[ps]ub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u)"
+               fi
+               current_keys="$(LC_ALL=C $GPG $PASSWORD_STORE_GPG_OPTS -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$passfile" 2>&1 | sed -n 's/^gpg: public key is \([A-F0-9]\+\)$/\1/p' | LC_ALL=C sort -u)"
+diff --git a/tests/t0300-reencryption.sh b/tests/t0300-reencryption.sh
+index 3c88987..57d873f 100755
+--- a/tests/t0300-reencryption.sh
++++ b/tests/t0300-reencryption.sh
+@@ -7,7 +7,7 @@ cd "$(dirname "$0")"
+ INITIAL_PASSWORD="will this password live? a big question indeed..."
+ canonicalize_gpg_keys() {
+-      $GPG --list-keys --with-colons "$@" | sed -n 's/sub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u
++      $GPG --list-keys --with-colons "$@" | sed -n 's/[ps]ub:[^:]*:[^:]*:[^:]*:\([^:]*\):[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[^:]*:[a-zA-Z]*e[a-zA-Z]*:.*/\1/p' | LC_ALL=C sort -u
+ }
+ gpg_keys_from_encrypted_file() {
+       $GPG -v --no-secmem-warning --no-permission-warning --decrypt --list-only --keyid-format long "$1" 2>&1 | grep "public key is" | cut -d ' ' -f 5 | LC_ALL=C sort -u
+-- 
+2.19.1
+
diff --git a/overlays/pass/pass.json b/overlays/pass/pass.json
new file mode 100644 (file)
index 0000000..a4638c1
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "tag": "d29a389-master",
+  "meta": {
+    "name": "password-store",
+    "url": "https://git.zx2c4.com/password-store/",
+    "branch": "master"
+  },
+  "git": {
+    "url": "https://git.zx2c4.com/password-store/",
+    "rev": "d29a389a40524c684595f51bb937f66958bc14ea",
+    "sha256": "17g43i0if9nggcq6005iyxxy9my8s15ihc2nzwjgqzhy3svh5xvn",
+    "fetchSubmodules": true
+  }
+}
diff --git a/overlays/pelican/default.nix b/overlays/pelican/default.nix
new file mode 100644 (file)
index 0000000..5f60b8f
--- /dev/null
@@ -0,0 +1,6 @@
+self: super: {
+  pelican = with self.python3Packages;
+    pelican.overrideAttrs(old: self.mylibs.fetchedGithub ./pelican.json // {
+      propagatedBuildInputs = old.propagatedBuildInputs ++ [ pyyaml ];
+    });
+}
diff --git a/overlays/pelican/pelican.json b/overlays/pelican/pelican.json
new file mode 100644 (file)
index 0000000..d8f4425
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "4.0.1",
+  "meta": {
+    "name": "pelican",
+    "url": "https://github.com/getpelican/pelican",
+    "branch": "refs/tags/4.0.1"
+  },
+  "github": {
+    "owner": "getpelican",
+    "repo": "pelican",
+    "rev": "24d6efa9fda4ad45649ddf88c1c596193d589bf8",
+    "sha256": "09fcwnnfln0cl5v0qpxzrllj27znrg6dbhaksxrl0192c3mbyjvl",
+    "fetchSubmodules": true
+  }
+}
diff --git a/overlays/profanity/default.nix b/overlays/profanity/default.nix
new file mode 100644 (file)
index 0000000..33861f1
--- /dev/null
@@ -0,0 +1,9 @@
+self: super: {
+  profanity = (super.profanity.override {
+    notifySupport = true;
+    inherit (self) libnotify gpgme gdk_pixbuf;
+    python = self.python3;
+  }).overrideAttrs (old: rec {
+    configureFlags = old.configureFlags ++ [ "--enable-plugins" ];
+  });
+}
diff --git a/overlays/python-packages/buildbot.nix b/overlays/python-packages/buildbot.nix
new file mode 100644 (file)
index 0000000..ccf2f6a
--- /dev/null
@@ -0,0 +1,8 @@
+self: super: {
+  pythonOverrides = self.buildPythonOverrides (pyself: pysuper: {
+    buildbot-plugins = pysuper.buildbot-plugins // {
+      buildslist = self.python3PackagesPlus.buildbot-plugins.buildslist;
+    };
+    buildbot-full = pysuper.buildbot-full.withPlugins [ pyself.buildbot-plugins.buildslist ];
+  }) super.pythonOverrides;
+}
diff --git a/overlays/python-packages/default.nix b/overlays/python-packages/default.nix
new file mode 100644 (file)
index 0000000..8a9949e
--- /dev/null
@@ -0,0 +1,28 @@
+let
+  fromMyPythonPackages = name: self: super: {
+    pythonOverrides = self.buildPythonOverrides (pyself: pysuper: {
+      "${name}" = self."${pyself.python.pname}PackagesPlus"."${name}";
+    }) super.pythonOverrides;
+  };
+in
+{
+  # https://github.com/NixOS/nixpkgs/issues/44426
+  # needs to come before all other in alphabetical order (or make use of
+  # lib.mkBefore)
+  __pythonOverlayFix = self: super: let
+    pyNames = [ "python3" "python36" "python37" ];
+    overriddenPython = name: [
+      { inherit name; value = super.${name}.override { packageOverrides = self.pythonOverrides; }; }
+      { name = "${name}Packages"; value = self.recurseIntoAttrs self.${name}.pkgs; }
+    ];
+    overriddenPythons = builtins.concatLists (map overriddenPython pyNames);
+  in {
+    pythonOverrides = pyself: pysuper: {};
+    buildPythonOverrides = newOverrides: currentOverrides: super.lib.composeExtensions newOverrides currentOverrides;
+  } // super.lib.attrsets.listToAttrs overriddenPythons;
+
+
+  apprise = fromMyPythonPackages "apprise";
+  buildbot = import ./buildbot.nix;
+  wokkel = fromMyPythonPackages "wokkel";
+}
diff --git a/overlays/sc-im/default.nix b/overlays/sc-im/default.nix
new file mode 100644 (file)
index 0000000..f728655
--- /dev/null
@@ -0,0 +1,9 @@
+self: super: {
+  sc-im = super.sc-im.overrideAttrs (old: {
+    buildPhase = ''
+      cd src
+      sed -i Makefile -e 's@\...name.info@.local/state/$(name)info@'
+      cd ..
+      '' + old.buildPhase;
+  });
+}
diff --git a/overlays/shaarli/default.nix b/overlays/shaarli/default.nix
new file mode 100644 (file)
index 0000000..c2fb9cc
--- /dev/null
@@ -0,0 +1,10 @@
+self: super: {
+  shaarli = varDir: super.shaarli.overrideAttrs (old: {
+    patchPhase = "";
+    patches = (old.patches or []) ++ [ ./shaarli_ldap.patch ];
+    installPhase = (old.installPhase or "") + ''
+      cp .htaccess $out/
+      ln -sf ${varDir}/{cache,pagecache,tmp,data} $out/
+      '';
+  });
+}
diff --git a/overlays/shaarli/shaarli_ldap.patch b/overlays/shaarli/shaarli_ldap.patch
new file mode 100644 (file)
index 0000000..9c7315a
--- /dev/null
@@ -0,0 +1,420 @@
+commit bc82ebfd779b8641dadd6787f51639ea9105c3e8
+Author: Ismaël Bouya <ismael.bouya@normalesup.org>
+Date:   Sun Feb 3 20:58:18 2019 +0100
+
+    Add ldap connection
+
+diff --git a/.htaccess b/.htaccess
+index 4c00427..5acd708 100644
+--- a/.htaccess
++++ b/.htaccess
+@@ -6,10 +6,23 @@ RewriteEngine On
+ # Prevent accessing subdirectories not managed by SCM
+ RewriteRule ^(.git|doxygen|vendor) - [F]
++RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$
++RewriteRule ^(.*) - [E=BASE:%1]
++
++RewriteCond %{ENV:REDIRECT_BASE} (.+)
++RewriteRule .* - [E=BASE:%1]
++
+ # Forward the "Authorization" HTTP header
+ RewriteCond %{HTTP:Authorization} ^(.*)
+ RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
++RewriteCond %{REQUEST_FILENAME} !-f
++RewriteCond %{REQUEST_FILENAME} !-d
++RewriteRule ^((?!api/)[^/]*)/?(.*)$ $2?%{QUERY_STRING} [E=USERSPACE:$1]
++
++RewriteCond %{ENV:REDIRECT_USERSPACE} (.+)
++RewriteRule .* - [E=USERSPACE:%1]
++
+ # REST API
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+diff --git a/application/ApplicationUtils.php b/application/ApplicationUtils.php
+index 911873a..f21a1ef 100644
+--- a/application/ApplicationUtils.php
++++ b/application/ApplicationUtils.php
+@@ -191,6 +191,9 @@ public static function checkResourcePermissions($conf)
+             $conf->get('resource.page_cache'),
+             $conf->get('resource.raintpl_tmp'),
+         ) as $path) {
++            if (! is_dir($path)) {
++                mkdir($path, 0755, true);
++            }
+             if (! is_readable(realpath($path))) {
+                 $errors[] = '"'.$path.'" '. t('directory is not readable');
+             }
+diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php
+index 32aaea4..99efc15 100644
+--- a/application/config/ConfigManager.php
++++ b/application/config/ConfigManager.php
+@@ -21,6 +21,11 @@ class ConfigManager
+     public static $DEFAULT_PLUGINS = array('qrcode');
++    /**
++     * @var string User space.
++     */
++    protected $userSpace;
++
+     /**
+      * @var string Config folder.
+      */
+@@ -41,12 +46,36 @@ class ConfigManager
+      *
+      * @param string $configFile Configuration file path without extension.
+      */
+-    public function __construct($configFile = 'data/config')
++    public function __construct($configFile = null, $userSpace = null)
+     {
+-        $this->configFile = $configFile;
++        $this->userSpace = $this->findLDAPUser($userSpace);
++        if ($configFile !== null) {
++            $this->configFile = $configFile;
++        } else {
++            $this->configFile = ($this->userSpace === null) ? 'data/config' : 'data/' . $this->userSpace . '/config';
++        }
+         $this->initialize();
+     }
++    public function findLDAPUser($login, $password = null) {
++        $connect = ldap_connect(getenv('SHAARLI_LDAP_HOST'));
++        ldap_set_option($connect, LDAP_OPT_PROTOCOL_VERSION, 3);
++        if (!$connect || !ldap_bind($connect, getenv('SHAARLI_LDAP_DN'), getenv('SHAARLI_LDAP_PASSWORD'))) {
++            return false;
++        }
++
++        $search_query = str_replace('%login%', ldap_escape($login), getenv('SHAARLI_LDAP_FILTER'));
++
++        $search = ldap_search($connect, getenv('SHAARLI_LDAP_BASE'), $search_query);
++        $info = ldap_get_entries($connect, $search);
++
++        if (ldap_count_entries($connect, $search) == 1 && (is_null($password) || ldap_bind($connect, $info[0]["dn"], $password))) {
++            return $login;
++        } else {
++            return null;
++        }
++    }
++
+     /**
+      * Reset the ConfigManager instance.
+      */
+@@ -269,6 +298,16 @@ public function getConfigFileExt()
+         return $this->configFile . $this->configIO->getExtension();
+     }
++    /**
++     * Get the current userspace.
++     *
++     * @return mixed User space.
++     */
++    public function getUserSpace()
++    {
++      return $this->userSpace;
++    }
++
+     /**
+      * Recursive function which find asked setting in the loaded config.
+      *
+@@ -342,19 +381,31 @@ protected static function removeConfig($settings, &$conf)
+      */
+     protected function setDefaultValues()
+     {
+-        $this->setEmpty('resource.data_dir', 'data');
+-        $this->setEmpty('resource.config', 'data/config.php');
+-        $this->setEmpty('resource.datastore', 'data/datastore.php');
+-        $this->setEmpty('resource.ban_file', 'data/ipbans.php');
+-        $this->setEmpty('resource.updates', 'data/updates.txt');
+-        $this->setEmpty('resource.log', 'data/log.txt');
+-        $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt');
+-        $this->setEmpty('resource.history', 'data/history.php');
++        if ($this->userSpace === null) {
++          $data = 'data';
++          $tmp  = 'tmp';
++          $cache = 'cache';
++          $pagecache = 'pagecache';
++        } else {
++          $data = 'data/' . ($this->userSpace);
++          $tmp  = 'tmp/' . ($this->userSpace);
++          $cache = 'cache/' . ($this->userSpace);
++          $pagecache = 'pagecache/' . ($this->userSpace);
++        }
++
++        $this->setEmpty('resource.data_dir', $data);
++        $this->setEmpty('resource.config', $data . '/config.php');
++        $this->setEmpty('resource.datastore', $data . '/datastore.php');
++        $this->setEmpty('resource.ban_file', $data . '/ipbans.php');
++        $this->setEmpty('resource.updates', $data . '/updates.txt');
++        $this->setEmpty('resource.log', $data . '/log.txt');
++        $this->setEmpty('resource.update_check', $data . '/lastupdatecheck.txt');
++        $this->setEmpty('resource.history', $data . '/history.php');
+         $this->setEmpty('resource.raintpl_tpl', 'tpl/');
+         $this->setEmpty('resource.theme', 'default');
+-        $this->setEmpty('resource.raintpl_tmp', 'tmp/');
+-        $this->setEmpty('resource.thumbnails_cache', 'cache');
+-        $this->setEmpty('resource.page_cache', 'pagecache');
++        $this->setEmpty('resource.raintpl_tmp', $tmp);
++        $this->setEmpty('resource.thumbnails_cache', $cache);
++        $this->setEmpty('resource.page_cache', $pagecache);
+         $this->setEmpty('security.ban_after', 4);
+         $this->setEmpty('security.ban_duration', 1800);
+diff --git a/application/security/LoginManager.php b/application/security/LoginManager.php
+index d6784d6..bdfaca7 100644
+--- a/application/security/LoginManager.php
++++ b/application/security/LoginManager.php
+@@ -32,6 +32,9 @@ class LoginManager
+     /** @var string User sign-in token depending on remote IP and credentials */
+     protected $staySignedInToken = '';
++    protected $lastErrorReason = '';
++    protected $lastErrorIsBanishable = false;
++
+     /**
+      * Constructor
+      *
+@@ -83,7 +86,7 @@ public function getStaySignedInToken()
+      */
+     public function checkLoginState($cookie, $clientIpId)
+     {
+-        if (! $this->configManager->exists('credentials.login')) {
++        if (! $this->configManager->exists('credentials.login') || (isset($_SESSION['username']) && $_SESSION['username'] && $this->configManager->get('credentials.login') !== $_SESSION['username'])) {
+             // Shaarli is not configured yet
+             $this->isLoggedIn = false;
+             return;
+@@ -133,20 +136,40 @@ public function isLoggedIn()
+      */
+     public function checkCredentials($remoteIp, $clientIpId, $login, $password)
+     {
+-        $hash = sha1($password . $login . $this->configManager->get('credentials.salt'));
++        $this->lastErrorIsBanishable = false;
++
++        if ($this->configManager->getUserSpace() !== null && $this->configManager->getUserSpace() !== $login) {
++          logm($this->configManager->get('resource.log'),
++               $remoteIp,
++               'Trying to login to wrong user space');
++          $this->lastErrorReason = 'You’re trying to access the wrong account.';
++          return false;
++        }
+-        if ($login != $this->configManager->get('credentials.login')
+-            || $hash != $this->configManager->get('credentials.hash')
+-        ) {
++        logm($this->configManager->get('resource.log'),
++             $remoteIp,
++             'Trying LDAP connection');
++        $result = $this->configManager->findLDAPUser($login, $password);
++        if ($result === false) {
+             logm(
+                 $this->configManager->get('resource.log'),
+                 $remoteIp,
+-                'Login failed for user ' . $login
++                'Impossible to connect to LDAP'
+             );
++            $this->lastErrorReason = 'Server error.';
++            return false;
++        } else if (is_null($result)) {
++            logm(
++              $this->configManager->get('resource.log'),
++              $remoteIp,
++              'Login failed for user ' . $login
++            );
++            $this->lastErrorIsBanishable = true;
++            $this->lastErrorReason = 'Wrong login/password.';
+             return false;
+         }
+-        $this->sessionManager->storeLoginInfo($clientIpId);
++        $this->sessionManager->storeLoginInfo($clientIpId, $login);
+         logm(
+             $this->configManager->get('resource.log'),
+             $remoteIp,
+@@ -187,6 +210,10 @@ protected function writeBanFile()
+      */
+     public function handleFailedLogin($server)
+     {
++        if (!$this->lastErrorIsBanishable) {
++          return $this->lastErrorReason ?: 'Error during login.';
++        };
++
+         $ip = $server['REMOTE_ADDR'];
+         $trusted = $this->configManager->get('security.trusted_proxies', []);
+@@ -215,6 +242,7 @@ public function handleFailedLogin($server)
+             );
+         }
+         $this->writeBanFile();
++        return $this->lastErrorReason ?: 'Error during login.';
+     }
+     /**
+diff --git a/application/security/SessionManager.php b/application/security/SessionManager.php
+index b8b8ab8..5eb4aac 100644
+--- a/application/security/SessionManager.php
++++ b/application/security/SessionManager.php
+@@ -111,10 +111,10 @@ public static function checkId($sessionId)
+      *
+      * @param string $clientIpId Client IP address identifier
+      */
+-    public function storeLoginInfo($clientIpId)
++    public function storeLoginInfo($clientIpId, $login = null)
+     {
+         $this->session['ip'] = $clientIpId;
+-        $this->session['username'] = $this->conf->get('credentials.login');
++        $this->session['username'] = $login ?: $this->conf->get('credentials.login');
+         $this->extendTimeValidityBy(self::$SHORT_TIMEOUT);
+     }
+diff --git a/index.php b/index.php
+index 4b86a3e..85376e8 100644
+--- a/index.php
++++ b/index.php
+@@ -121,7 +121,27 @@
+     $_COOKIE['shaarli'] = session_id();
+ }
+-$conf = new ConfigManager();
++$folderBase = getenv("BASE");
++
++if (getenv("USERSPACE")) {
++    if (isset($_GET["do"]) && $_GET["do"] == "login") {
++        header("Location: $folderBase/?do=login");
++        exit;
++    }
++    $userspace = preg_replace("/[^-_A-Za-z0-9]/", '', getenv("USERSPACE"));
++} else if (isset($_SESSION["username"]) && $_SESSION["username"]) {
++    header("Location: " . $folderBase . "/" . $_SESSION["username"] . "?");
++    exit;
++} else if (!isset($_GET["do"]) || $_GET["do"] != "login") {
++    header("Location: $folderBase/?do=login");
++    exit;
++}
++
++if (isset($userspace)) {
++  $conf = new ConfigManager(null, $userspace);
++} else {
++  $conf = new ConfigManager();
++}
+ $sessionManager = new SessionManager($_SESSION, $conf);
+ $loginManager = new LoginManager($GLOBALS, $conf, $sessionManager);
+ $loginManager->generateStaySignedInToken($_SERVER['REMOTE_ADDR']);
+@@ -175,7 +195,7 @@
+     }
+     // Display the installation form if no existing config is found
+-    install($conf, $sessionManager, $loginManager);
++    install($conf, $sessionManager, $loginManager, $userspace);
+ }
+ $loginManager->checkLoginState($_COOKIE, $clientIpId);
+@@ -205,6 +225,7 @@ function isLoggedIn()
+         && $loginManager->checkCredentials($_SERVER['REMOTE_ADDR'], $clientIpId, $_POST['login'], $_POST['password'])
+     ) {
+         $loginManager->handleSuccessfulLogin($_SERVER);
++        $userspace = $_POST['login'];
+         $cookiedir = '';
+         if (dirname($_SERVER['SCRIPT_NAME']) != '/') {
+@@ -241,25 +262,25 @@ function isLoggedIn()
+                     $uri .= '&'.$param.'='.urlencode($_GET[$param]);
+                 }
+             }
+-            header('Location: '. $uri);
++            header('Location: '. $userspace . $uri);
+             exit;
+         }
+         if (isset($_GET['edit_link'])) {
+-            header('Location: ?edit_link='. escape($_GET['edit_link']));
++            header('Location: ' . $userspace . '?edit_link='. escape($_GET['edit_link']));
+             exit;
+         }
+         if (isset($_POST['returnurl'])) {
+             // Prevent loops over login screen.
+             if (strpos($_POST['returnurl'], 'do=login') === false) {
+-                header('Location: '. generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST']));
++                header('Location: ' . generateLocation($_POST['returnurl'], $_SERVER['HTTP_HOST']));
+                 exit;
+             }
+         }
+-        header('Location: ?'); exit;
++        header('Location: '. $userspace . '?'); exit;
+     } else {
+-        $loginManager->handleFailedLogin($_SERVER);
++        $errorReason = $loginManager->handleFailedLogin($_SERVER);
+         $redir = '&username='. urlencode($_POST['login']);
+         if (isset($_GET['post'])) {
+             $redir .= '&post=' . urlencode($_GET['post']);
+@@ -270,7 +291,7 @@ function isLoggedIn()
+             }
+         }
+         // Redirect to login screen.
+-        echo '<script>alert("'. t("Wrong login/password.") .'");document.location=\'?do=login'.$redir.'\';</script>';
++        echo '<script>alert("'. t($errorReason) .'");document.location=\'?do=login'.$redir.'\';</script>';
+         exit;
+     }
+ }
+@@ -1719,7 +1740,7 @@ function buildLinkList($PAGE, $LINKSDB, $conf, $pluginManager, $loginManager)
+  * @param SessionManager $sessionManager SessionManager instance
+  * @param LoginManager   $loginManager   LoginManager instance
+  */
+-function install($conf, $sessionManager, $loginManager) {
++function install($conf, $sessionManager, $loginManager, $userspace) {
+     // On free.fr host, make sure the /sessions directory exists, otherwise login will not work.
+     if (endsWith($_SERVER['HTTP_HOST'],'.free.fr') && !is_dir($_SERVER['DOCUMENT_ROOT'].'/sessions')) mkdir($_SERVER['DOCUMENT_ROOT'].'/sessions',0705);
+@@ -1755,7 +1776,7 @@ function install($conf, $sessionManager, $loginManager) {
+     }
+-    if (!empty($_POST['setlogin']) && !empty($_POST['setpassword']))
++    if (true)
+     {
+         $tz = 'UTC';
+         if (!empty($_POST['continent']) && !empty($_POST['city'])
+@@ -1764,15 +1785,15 @@ function install($conf, $sessionManager, $loginManager) {
+             $tz = $_POST['continent'].'/'.$_POST['city'];
+         }
+         $conf->set('general.timezone', $tz);
+-        $login = $_POST['setlogin'];
+-        $conf->set('credentials.login', $login);
++        $conf->set('credentials.login', $userspace);
+         $salt = sha1(uniqid('', true) .'_'. mt_rand());
+         $conf->set('credentials.salt', $salt);
+-        $conf->set('credentials.hash', sha1($_POST['setpassword'] . $login . $salt));
++        $hash = sha1(uniqid('', true) .'_'. mt_rand());
++        $conf->set('credentials.hash', $hash);
+         if (!empty($_POST['title'])) {
+             $conf->set('general.title', escape($_POST['title']));
+         } else {
+-            $conf->set('general.title', 'Shared links on '.escape(index_url($_SERVER)));
++            $conf->set('general.title', ucwords(str_replace("_", " ", $userspace)));
+         }
+         $conf->set('translation.language', escape($_POST['language']));
+         $conf->set('updates.check_updates', !empty($_POST['updateCheck']));
+@@ -1841,7 +1862,12 @@ function install($conf, $sessionManager, $loginManager) {
+ $app = new \Slim\App($container);
+ // REST API routes
+-$app->group('/api/v1', function() {
++if (isset($userspace)) {
++  $mountpoint = '/' . $userspace . '/api/v1';
++} else {
++  $mountpoint = '/api/v1';
++}
++$app->group($mountpoint, function() {
+     $this->get('/info', '\Shaarli\Api\Controllers\Info:getInfo')->setName('getInfo');
+     $this->get('/links', '\Shaarli\Api\Controllers\Links:getLinks')->setName('getLinks');
+     $this->get('/links/{id:[\d]+}', '\Shaarli\Api\Controllers\Links:getLink')->setName('getLink');
+@@ -1860,7 +1886,7 @@ function install($conf, $sessionManager, $loginManager) {
+ $response = $app->run(true);
+ // Hack to make Slim and Shaarli router work together:
+ // If a Slim route isn't found and NOT API call, we call renderPage().
+-if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], '/api/v1') === false) {
++if ($response->getStatusCode() == 404 && strpos($_SERVER['REQUEST_URI'], $mountpoint) === false) {
+     // We use UTF-8 for proper international characters handling.
+     header('Content-Type: text/html; charset=utf-8');
+     renderPage($conf, $pluginManager, $linkDb, $history, $sessionManager, $loginManager);
diff --git a/overlays/slrn/default.nix b/overlays/slrn/default.nix
new file mode 100644 (file)
index 0000000..6caef55
--- /dev/null
@@ -0,0 +1,11 @@
+self: super: {
+  slrn = super.slrn.overrideAttrs (old: rec {
+    version = "1.0.3a";
+    name = "slrn-${version}";
+    src = self.fetchurl {
+      url = "http://www.jedsoft.org/releases/slrn/slrn-${version}.tar.bz2";
+      sha256 = "1b1d9iikr60w0vq86y9a0l4gjl0jxhdznlrdp3r405i097as9a1v";
+    };
+    configureFlags = old.configureFlags ++ [ "--with-slrnpull" ];
+  });
+}
diff --git a/overlays/taskwarrior/default.nix b/overlays/taskwarrior/default.nix
new file mode 100644 (file)
index 0000000..64ea690
--- /dev/null
@@ -0,0 +1,13 @@
+self: super:
+{
+  taskwarrior = super.taskwarrior.overrideAttrs (old: {
+    postInstall = ''${old.postInstall}
+      mkdir -p "$out/share/vim/vimfiles/ftdetect"
+      mkdir -p "$out/share/vim/vimfiles/syntax"
+      ln -s "../../../../share/doc/task/scripts/vim/ftdetect/task.vim" "$out/share/vim/vimfiles/ftdetect/"
+      ln -s "../../../../share/doc/task/scripts/vim/syntax/taskrc.vim" "$out/share/vim/vimfiles/syntax/"
+      ln -s "../../../../share/doc/task/scripts/vim/syntax/taskdata.vim" "$out/share/vim/vimfiles/syntax/"
+      ln -s "../../../../share/doc/task/scripts/vim/syntax/taskedit.vim" "$out/share/vim/vimfiles/syntax/"
+    '';
+  });
+}
diff --git a/overlays/vit/default.nix b/overlays/vit/default.nix
new file mode 100644 (file)
index 0000000..4624284
--- /dev/null
@@ -0,0 +1,8 @@
+self: super:
+{
+  vit = (super.vit.override { inherit (self) taskwarrior; }).overrideAttrs (old:
+    self.mylibs.fetchedGithub ./vit.json // {
+      buildInputs = old.buildInputs ++ (with self.perlPackages; [ TryTiny TextCharWidth ]);
+    }
+  );
+}
diff --git a/overlays/vit/vit.json b/overlays/vit/vit.json
new file mode 100644 (file)
index 0000000..d062f68
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "dbacada-1.3",
+  "meta": {
+    "name": "vit",
+    "url": "https://github.com/scottkosty/vit",
+    "branch": "1.3"
+  },
+  "github": {
+    "owner": "scottkosty",
+    "repo": "vit",
+    "rev": "dbacada5867b238fdf35dbf00a3ca0daf7703038",
+    "sha256": "1wlk62cv6dc0dqv8265xcx2l7ydzg40xf6l4qbrf6h5156ncc90l",
+    "fetchSubmodules": true
+  }
+}
diff --git a/overlays/weboob/default.nix b/overlays/weboob/default.nix
new file mode 100644 (file)
index 0000000..d0a15a7
--- /dev/null
@@ -0,0 +1,15 @@
+self: super: {
+  weboob = (self.pythonPackages.weboob.overridePythonAttrs {
+    setupPyBuildFlags = [ "--no-qt" "--xdg" ];
+  }).overrideAttrs (old: rec {
+    version = "1.5";
+    src = self.fetchurl {
+      url = "https://git.weboob.org/weboob/weboob/-/archive/${version}/${old.pname}-${version}.tar.gz";
+      sha256 = "0l6q5nm5g0zn6gmf809059kddrbds27wgygxsfkqja9blks5vq7z";
+    };
+    postInstall = ''${old.postInstall or ""}
+      mkdir -p $out/share/bash-completion/completions/
+      cp tools/weboob_bash_completion $out/share/bash-completion/completions/weboob
+    '';
+  });
+}
diff --git a/overlays/weechat/default.nix b/overlays/weechat/default.nix
new file mode 100644 (file)
index 0000000..17faa0e
--- /dev/null
@@ -0,0 +1,14 @@
+self: super: {
+  weechat = super.weechat.override {
+    configure = { availablePlugins, ... }: {
+      plugins = with self; with availablePlugins; [
+          # Make sure websocket_client is not 0.55.0, it provokes
+          # regular crashes
+         (python.withPackages (ps: with ps; assert websocket_client.version == "0.54.0"; [websocket_client emoji]))
+         perl
+         ruby
+        ];
+    };
+  };
+
+}
diff --git a/overlays/ympd/default.nix b/overlays/ympd/default.nix
new file mode 100644 (file)
index 0000000..dda17aa
--- /dev/null
@@ -0,0 +1,5 @@
+self: super: {
+  ympd = super.ympd.overrideAttrs(old: self.mylibs.fetchedGithub ./ympd.json // {
+    patches = (old.patches or []) ++ [ ./ympd-password-env.patch ];
+  });
+}
diff --git a/overlays/ympd/ympd-password-env.patch b/overlays/ympd/ympd-password-env.patch
new file mode 100644 (file)
index 0000000..2bbe188
--- /dev/null
@@ -0,0 +1,23 @@
+diff --git a/src/ympd.c b/src/ympd.c
+index 3aed7e6..b3b6fda 100644
+--- a/src/ympd.c
++++ b/src/ympd.c
+@@ -71,6 +71,7 @@ int main(int argc, char **argv)
+     char *run_as_user = NULL;
+     char const *error_msg = NULL;
+     char *webport = "8080";
++    const char *s;
+     atexit(bye);
+ #ifdef WITH_DYNAMIC_ASSETS
+@@ -92,6 +93,10 @@ int main(int argc, char **argv)
+         {0,              0,                 0,  0 }
+     };
++    if ((s = getenv("MPD_PASSWORD")) != NULL) {
++        mpd.password = strdup(s);
++    }
++
+     while((n = getopt_long(argc, argv, "h:p:w:u:vm:",
+                 long_options, &option_index)) != -1) {
+         switch (n) {
diff --git a/overlays/ympd/ympd.json b/overlays/ympd/ympd.json
new file mode 100644 (file)
index 0000000..51f06d5
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "612f8fc-master",
+  "meta": {
+    "name": "ympd",
+    "url": "https://github.com/notandy/ympd",
+    "branch": "master"
+  },
+  "github": {
+    "owner": "notandy",
+    "repo": "ympd",
+    "rev": "612f8fc0b2c47fc89d403e4a044541c6b2b238c8",
+    "sha256": "01hnj10zl103mrn82vyd42fvq7w5az3jf1qz18889zv67kn73ll9",
+    "fetchSubmodules": true
+  }
+}
diff --git a/pkgs/bitlbee-mastodon/default.nix b/pkgs/bitlbee-mastodon/default.nix
new file mode 100644 (file)
index 0000000..0451068
--- /dev/null
@@ -0,0 +1,28 @@
+{ stdenv, fetchFromGitHub, autoreconfHook, pkgconfig, bitlbee, glib, lib }:
+stdenv.mkDerivation rec {
+  name = "bitlbee-mastodon-${version}";
+  version = "v1.4.2";
+
+  src = fetchFromGitHub {
+    rev = version;
+    owner = "kensanata";
+    repo = "bitlbee-mastodon";
+    sha256 = "04rakgr1pfsg1vhfwlfbggbzw249j7dmk88xrsnf3n84c5ccdyas";
+  };
+
+  nativeBuildInputs = [ autoreconfHook pkgconfig ];
+  buildInputs = [ bitlbee glib ];
+
+  preConfigure = ''
+    export BITLBEE_PLUGINDIR=$out/lib/bitlbee
+    ./autogen.sh
+  '';
+
+  meta = {
+    description = "Bitlbee plugin for Mastodon";
+
+    homepage = https://github.com/kensanata/bitlbee-mastodon;
+    license = lib.licenses.gpl2Plus;
+    platforms = lib.platforms.linux;
+  };
+}
diff --git a/pkgs/boinctui/default.nix b/pkgs/boinctui/default.nix
new file mode 100644 (file)
index 0000000..d8b106a
--- /dev/null
@@ -0,0 +1,20 @@
+{ stdenv, fetchurl, expat, openssl, autoconf, ncurses }:
+stdenv.mkDerivation rec {
+  name = "boinctui-${version}";
+  version = "2.5.0";
+  src = fetchurl {
+    url = "http://sourceforge.net/projects/boinctui/files/boinctui_${version}.tar.gz";
+    sha256 = "16zxp8r4z6pllacdacg681y56cg2phnn3pm5gwszbsi93cix2g8p";
+  };
+
+  configureFlags = [ "--without-gnutls" ];
+  preConfigure = ''
+    autoconf
+    '';
+
+  preBuild = ''
+    sed -i -e 's/"HOME"/"XDG_CONFIG_HOME"/' src/cfg.cpp
+    sed -i -e 's@\.boinctui\.cfg@boinctui/boinctui.cfg@' src/mainprog.cpp
+    '';
+  buildInputs = [ expat openssl autoconf ncurses ];
+}
diff --git a/pkgs/cnagios/cnagios.json b/pkgs/cnagios/cnagios.json
new file mode 100644 (file)
index 0000000..4c1c385
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "3bd27fb-master",
+  "meta": {
+    "name": "cnagios",
+    "url": "https://github.com/dannywarren/cnagios",
+    "branch": "master"
+  },
+  "github": {
+    "owner": "dannywarren",
+    "repo": "cnagios",
+    "rev": "3bd27fb40e68f61ffd01bea6234b919a667b6fe4",
+    "sha256": "0iy5pmlcz6y3if72nav22xqxniiv1v8ywi0927m6s459hkw5n2rb",
+    "fetchSubmodules": true
+  }
+}
diff --git a/pkgs/cnagios/default.nix b/pkgs/cnagios/default.nix
new file mode 100644 (file)
index 0000000..d5b52f3
--- /dev/null
@@ -0,0 +1,22 @@
+{ stdenv, mylibs, perl, ncurses }:
+stdenv.mkDerivation (mylibs.fetchedGithub ./cnagios.json // {
+  configureFlags = [
+    "--with-etc-dir=/etc/cnagios"
+    "--with-var-dir=/var/lib/naemon"
+    "--with-status-file=/var/lib/naemon/status.dat"
+    "--with-nagios-data=4"
+  ];
+
+  prePatch = ''
+    sed -i -e "s/-lcurses/-lncurses/" Makefile.in
+  '';
+  installPhase = ''
+    install -dm755 $out/share/doc/cnagios
+    install -Dm644 cnagiosrc $out/share/doc/cnagios/
+    install -Dm644 cnagios.help $out/share/doc/cnagios/
+    install -Dm644 cnagios.pl $out/share/doc/cnagios/
+    install -dm755 $out/bin
+    install -Dm755 cnagios $out/bin/
+  '';
+  buildInputs = [ perl ncurses ];
+})
diff --git a/pkgs/composer-env/default.nix b/pkgs/composer-env/default.nix
new file mode 100644 (file)
index 0000000..416a61c
--- /dev/null
@@ -0,0 +1,280 @@
+# This file originates from composer2nix
+
+{ stdenv, writeTextFile, fetchurl, php, unzip }:
+
+let
+  composer = stdenv.mkDerivation {
+    name = "composer-1.8.0";
+    src = fetchurl {
+      url = https://github.com/composer/composer/releases/download/1.8.0/composer.phar;
+      sha256 = "19pg9ip2mpyf5cyq34fld7qwl77mshqw3c4nif7sxmpnar6sh089";
+    };
+    buildInputs = [ php ];
+
+    # We must wrap the composer.phar because of the impure shebang.
+    # We cannot use patchShebangs because the executable verifies its own integrity and will detect that somebody has tampered with it.
+
+    buildCommand = ''
+      # Copy phar file
+      mkdir -p $out/share/php
+      cp $src $out/share/php/composer.phar
+      chmod 755 $out/share/php/composer.phar
+
+      # Create wrapper executable
+      mkdir -p $out/bin
+      cat > $out/bin/composer <<EOF
+      #! ${stdenv.shell} -e
+      exec ${php}/bin/php $out/share/php/composer.phar "\$@"
+      EOF
+      chmod +x $out/bin/composer
+    '';
+    meta = {
+      description = "Dependency Manager for PHP";
+      #license = stdenv.licenses.mit;
+      maintainers = [ stdenv.lib.maintainers.sander ];
+      platforms = stdenv.lib.platforms.unix;
+    };
+  };
+
+  buildZipPackage = { name, src }:
+    stdenv.mkDerivation {
+      inherit name src;
+      buildInputs = [ unzip ];
+      buildCommand = ''
+        unzip $src
+        baseDir=$(find . -type d -mindepth 1 -maxdepth 1)
+        cd $baseDir
+        mkdir -p $out
+        mv * $out
+      '';
+    };
+
+  buildPackage =
+    { name
+    , src
+    , packages ? {}
+    , devPackages ? {}
+    , buildInputs ? []
+    , symlinkDependencies ? false
+    , executable ? false
+    , removeComposerArtifacts ? false
+    , postInstall ? ""
+    , preInstall ? ""
+    , noDev ? false
+    , unpackPhase ? "true"
+    , buildPhase ? "true"
+    , doRemoveVendor ? true
+    , ...}@args:
+
+    let
+      reconstructInstalled = writeTextFile {
+        name = "reconstructinstalled.php";
+        executable = true;
+        text = ''
+          #! ${php}/bin/php
+          <?php
+          if(file_exists($argv[1]))
+          {
+              $composerLockStr = file_get_contents($argv[1]);
+
+              if($composerLockStr === false)
+              {
+                  fwrite(STDERR, "Cannot open composer.lock contents\n");
+                  exit(1);
+              }
+              else
+              {
+                  $config = json_decode($composerLockStr, true);
+
+                  if(array_key_exists("packages", $config))
+                      $allPackages = $config["packages"];
+                  else
+                      $allPackages = array();
+
+                  ${stdenv.lib.optionalString (!noDev) ''
+                    if(array_key_exists("packages-dev", $config))
+                        $allPackages = array_merge($allPackages, $config["packages-dev"]);
+                  ''}
+
+                  $packagesStr = json_encode($allPackages, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+                  print($packagesStr);
+              }
+          }
+          else
+              print("[]");
+          ?>
+        '';
+      };
+
+      constructBin = writeTextFile {
+        name = "constructbin.php";
+        executable = true;
+        text = ''
+          #! ${php}/bin/php
+          <?php
+          $composerJSONStr = file_get_contents($argv[1]);
+
+          if($composerJSONStr === false)
+          {
+              fwrite(STDERR, "Cannot open composer.json contents\n");
+              exit(1);
+          }
+          else
+          {
+              $config = json_decode($composerJSONStr, true);
+
+              if(array_key_exists("bin-dir", $config))
+                  $binDir = $config["bin-dir"];
+              else
+                  $binDir = "bin";
+
+              if(array_key_exists("bin", $config))
+              {
+                  if(!file_exists("vendor/".$binDir))
+                      mkdir("vendor/".$binDir);
+
+                  foreach($config["bin"] as $bin)
+                      symlink("../../".$bin, "vendor/".$binDir."/".basename($bin));
+              }
+          }
+          ?>
+        '';
+      };
+
+      bundleDependencies = dependencies:
+        stdenv.lib.concatMapStrings (dependencyName:
+          let
+            dependency = dependencies.${dependencyName};
+          in
+          ''
+            ${if dependency.targetDir == "" then ''
+              vendorDir="$(dirname ${dependencyName})"
+              mkdir -p "$vendorDir"
+              ${if symlinkDependencies then
+                ''ln -s "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
+                else
+                ''cp -a "${dependency.src}" "$vendorDir/$(basename "${dependencyName}")"''
+              }${if dependency.needsModifyRights or false then "\n" + ''
+                chmod -R u+rwx "$vendorDir/$(basename "${dependencyName}")"
+            '' else ""}
+            '' else ''
+              namespaceDir="${dependencyName}/$(dirname "${dependency.targetDir}")"
+              mkdir -p "$namespaceDir"
+              ${if symlinkDependencies then
+                ''ln -s "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
+              else
+                ''cp -a "${dependency.src}" "$namespaceDir/$(basename "${dependency.targetDir}")"''
+              }${if dependency.needsModifyRights or false then "\n" + ''
+                chmod -R u+rwx "$namespaceDir/$(basename "${dependency.targetDir}")"
+            '' else ""}
+            ''}
+          '') (builtins.attrNames dependencies);
+
+      extraArgs = removeAttrs args [ "name" "packages" "devPackages" "buildInputs" ];
+    in
+    stdenv.mkDerivation ({
+      name = "composer-${name}";
+      buildInputs = [ php composer ] ++ buildInputs;
+
+      inherit unpackPhase buildPhase;
+
+      installPhase = ''
+        ${if executable then ''
+          mkdir -p $out/share/php
+          cp -a $src $out/share/php/$name
+          chmod -R u+w $out/share/php/$name
+          cd $out/share/php/$name
+        '' else ''
+          cp -a $src $out
+          chmod -R u+w $out
+          cd $out
+        ''}
+
+        # Execute pre install hook
+        runHook preInstall
+
+        # Remove unwanted files
+        rm -f *.nix
+
+        export HOME=$TMPDIR
+
+        ${if doRemoveVendor then ''
+        # Remove the provided vendor folder if it exists
+        rm -Rf vendor
+        '' else ""}
+        # If there is no composer.lock file, compose a dummy file.
+        # Otherwise, composer attempts to download the package.json file from
+        # the registry which we do not want.
+        if [ ! -f composer.lock ]
+        then
+            cat > composer.lock <<EOF
+        {
+            "packages": []
+        }
+        EOF
+        fi
+
+        # Reconstruct the installed.json file from the lock file
+        mkdir -p vendor/composer
+        ${reconstructInstalled} composer.lock > vendor/composer/installed.json
+
+        # Copy or symlink the provided dependencies
+        cd vendor
+        ${bundleDependencies packages}
+        ${stdenv.lib.optionalString (!noDev) (bundleDependencies devPackages)}
+        cd ..
+
+        # Reconstruct autoload scripts
+        # We use the optimize feature because Nix packages cannot change after they have been built
+        # Using the dynamic loader for a Nix package is useless since there is nothing to dynamically reload.
+        composer dump-autoload --optimize ${stdenv.lib.optionalString noDev "--no-dev"}
+
+        # Run the install step as a validation to confirm that everything works out as expected
+        composer install --optimize-autoloader ${stdenv.lib.optionalString noDev "--no-dev"}
+
+        ${stdenv.lib.optionalString executable ''
+          # Reconstruct the bin/ folder if we deploy an executable project
+          ${constructBin} composer.json
+          ln -s $(pwd)/vendor/bin $out/bin
+        ''}
+
+        ${stdenv.lib.optionalString (!symlinkDependencies) ''
+          # Patch the shebangs if possible
+          if [ -d $(pwd)/vendor/bin ]
+          then
+              # Look for all executables in bin/
+              for i in $(pwd)/vendor/bin/*
+              do
+                  # Look for their location
+                  realFile=$(readlink -f "$i")
+
+                  # Restore write permissions
+                  chmod u+wx "$(dirname "$realFile")"
+                  chmod u+w "$realFile"
+
+                  # Patch shebang
+                  sed -e "s|#!/usr/bin/php|#!${php}/bin/php|" \
+                      -e "s|#!/usr/bin/env php|#!${php}/bin/php|" \
+                      "$realFile" > tmp
+                  mv tmp "$realFile"
+                  chmod u+x "$realFile"
+              done
+          fi
+        ''}
+
+        if [ "$removeComposerArtifacts" = "1" ]
+        then
+            # Remove composer stuff
+            rm -f composer.json composer.lock
+        fi
+
+        # Execute post install hook
+        runHook postInstall
+    '';
+  } // extraArgs);
+in
+{
+  composer = stdenv.lib.makeOverridable composer;
+  buildZipPackage = stdenv.lib.makeOverridable buildZipPackage;
+  buildPackage = stdenv.lib.makeOverridable buildPackage;
+}
diff --git a/pkgs/crypto/cardano/daedalus.json b/pkgs/crypto/cardano/daedalus.json
new file mode 100644 (file)
index 0000000..5bb72f4
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "0.12.1",
+  "meta": {
+    "name": "daedalus",
+    "url": "https://github.com/input-output-hk/daedalus",
+    "branch": "refs/tags/0.12.1"
+  },
+  "github": {
+    "owner": "input-output-hk",
+    "repo": "daedalus",
+    "rev": "1276852b9a766d9fd4cda10561254f1a8ddd33ed",
+    "sha256": "0jf6ibwf0r4587g1ixq6zvi40kzwy137jgay5136yfbg15xw14k2",
+    "fetchSubmodules": true
+  }
+}
diff --git a/pkgs/crypto/cardano/default.nix b/pkgs/crypto/cardano/default.nix
new file mode 100644 (file)
index 0000000..5d08eda
--- /dev/null
@@ -0,0 +1,2 @@
+{ runCommand, mylibs }:
+runCommand "empty" { preferLocalBuild = true; } "mkdir -p $out"
diff --git a/pkgs/crypto/iota-cli-app/default.nix b/pkgs/crypto/iota-cli-app/default.nix
new file mode 100644 (file)
index 0000000..1a9d3ed
--- /dev/null
@@ -0,0 +1,20 @@
+{ stdenv, mylibs, fetchurl, fetchgit, callPackage, nodePackages, nodejs-8_x }:
+let
+  nodeEnv = callPackage mylibs.nodeEnv { nodejs = nodejs-8_x; };
+  # built using node2nix -8 -l package-lock.json
+  # and changing "./." to "src"
+  packageEnv = import ./node-packages.nix {
+    src = stdenv.mkDerivation (mylibs.fetchedGithub ./iota-cli-app.json // {
+      phases = "installPhase";
+      installPhase = ''
+        cp -a $src $out
+        chmod u+w -R $out
+        cd $out
+        sed -i -e "s@host: 'http://localhost',@host: 'https://iri.trytes.eu',@" index.js
+        sed -i -e "s@port: 14265@port: 443@" index.js
+        '';
+    });
+    inherit fetchurl fetchgit nodeEnv;
+  };
+in
+packageEnv.package
diff --git a/pkgs/crypto/iota-cli-app/iota-cli-app.json b/pkgs/crypto/iota-cli-app/iota-cli-app.json
new file mode 100644 (file)
index 0000000..6b47dec
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "tag": "d7e2e08-master",
+  "meta": {
+    "name": "iota-cli-app",
+    "url": "https://github.com/iotaledger/cli-app",
+    "branch": "master"
+  },
+  "github": {
+    "owner": "iotaledger",
+    "repo": "cli-app",
+    "rev": "d7e2e0856ae6bd34890fefb4245c07cd467a5032",
+    "sha256": "1n9kczsxdgjv8282nj2grlijvxipiskx0ndn169vz6v1l1hrwc8b",
+    "fetchSubmodules": true
+  }
+}
diff --git a/pkgs/crypto/iota-cli-app/node-packages.nix b/pkgs/crypto/iota-cli-app/node-packages.nix
new file mode 100644 (file)
index 0000000..d5c61d6
--- /dev/null
@@ -0,0 +1,1814 @@
+# This file has been generated by node2nix 1.6.0. Do not edit!
+
+{src, nodeEnv, fetchurl, fetchgit, globalBuildInputs ? []}:
+
+let
+  sources = {
+    "acorn-3.3.0" = {
+      name = "acorn";
+      packageName = "acorn";
+      version = "3.3.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz";
+        sha1 = "45e37fb39e8da3f25baee3ff5369e2bb5f22017a";
+      };
+    };
+    "acorn-5.2.1" = {
+      name = "acorn";
+      packageName = "acorn";
+      version = "5.2.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz";
+        sha512 = "jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==";
+      };
+    };
+    "acorn-jsx-3.0.1" = {
+      name = "acorn-jsx";
+      packageName = "acorn-jsx";
+      version = "3.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz";
+        sha1 = "afdf9488fb1ecefc8348f6fb22f464e32a58b36b";
+      };
+    };
+    "ajv-4.11.8" = {
+      name = "ajv";
+      packageName = "ajv";
+      version = "4.11.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz";
+        sha1 = "82ffb02b29e662ae53bdc20af15947706739c536";
+      };
+    };
+    "ajv-keywords-1.5.1" = {
+      name = "ajv-keywords";
+      packageName = "ajv-keywords";
+      version = "1.5.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz";
+        sha1 = "314dd0a4b3368fad3dfcdc54ede6171b886daf3c";
+      };
+    };
+    "ansi-escapes-1.4.0" = {
+      name = "ansi-escapes";
+      packageName = "ansi-escapes";
+      version = "1.4.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz";
+        sha1 = "d3a8a83b319aa67793662b13e761c7911422306e";
+      };
+    };
+    "ansi-regex-2.1.1" = {
+      name = "ansi-regex";
+      packageName = "ansi-regex";
+      version = "2.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz";
+        sha1 = "c3b33ab5ee360d86e0e628f0468ae7ef27d654df";
+      };
+    };
+    "ansi-regex-3.0.0" = {
+      name = "ansi-regex";
+      packageName = "ansi-regex";
+      version = "3.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz";
+        sha1 = "ed0317c322064f79466c02966bddb605ab37d998";
+      };
+    };
+    "ansi-styles-2.2.1" = {
+      name = "ansi-styles";
+      packageName = "ansi-styles";
+      version = "2.2.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz";
+        sha1 = "b432dd3358b634cf75e1e4664368240533c1ddbe";
+      };
+    };
+    "ansi-styles-3.2.0" = {
+      name = "ansi-styles";
+      packageName = "ansi-styles";
+      version = "3.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz";
+        sha512 = "NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==";
+      };
+    };
+    "argparse-1.0.9" = {
+      name = "argparse";
+      packageName = "argparse";
+      version = "1.0.9";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz";
+        sha1 = "73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86";
+      };
+    };
+    "array-union-1.0.2" = {
+      name = "array-union";
+      packageName = "array-union";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz";
+        sha1 = "9a34410e4f4e3da23dea375be5be70f24778ec39";
+      };
+    };
+    "array-uniq-1.0.3" = {
+      name = "array-uniq";
+      packageName = "array-uniq";
+      version = "1.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz";
+        sha1 = "af6ac877a25cc7f74e058894753858dfdb24fdb6";
+      };
+    };
+    "arrify-1.0.1" = {
+      name = "arrify";
+      packageName = "arrify";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz";
+        sha1 = "898508da2226f380df904728456849c1501a4b0d";
+      };
+    };
+    "async-2.6.0" = {
+      name = "async";
+      packageName = "async";
+      version = "2.6.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/async/-/async-2.6.0.tgz";
+        sha512 = "xAfGg1/NTLBBKlHFmnd7PlmUW9KhVQIUuSrYem9xzFUZy13ScvtyGGejaae9iAVRiRq9+Cx7DPFaAAhCpyxyPw==";
+      };
+    };
+    "babel-code-frame-6.26.0" = {
+      name = "babel-code-frame";
+      packageName = "babel-code-frame";
+      version = "6.26.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz";
+        sha1 = "63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b";
+      };
+    };
+    "babel-polyfill-6.26.0" = {
+      name = "babel-polyfill";
+      packageName = "babel-polyfill";
+      version = "6.26.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz";
+        sha1 = "379937abc67d7895970adc621f284cd966cf2153";
+      };
+    };
+    "babel-runtime-6.26.0" = {
+      name = "babel-runtime";
+      packageName = "babel-runtime";
+      version = "6.26.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz";
+        sha1 = "965c7058668e82b55d7bfe04ff2337bc8b5647fe";
+      };
+    };
+    "balanced-match-1.0.0" = {
+      name = "balanced-match";
+      packageName = "balanced-match";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz";
+        sha1 = "89b4d199ab2bee49de164ea02b89ce462d71b767";
+      };
+    };
+    "bignumber.js-4.1.0" = {
+      name = "bignumber.js";
+      packageName = "bignumber.js";
+      version = "4.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/bignumber.js/-/bignumber.js-4.1.0.tgz";
+        sha512 = "eJzYkFYy9L4JzXsbymsFn3p54D+llV27oTQ+ziJG7WFRheJcNZilgVXMG0LoZtlQSKBsJdWtLFqOD0u+U0jZKA==";
+      };
+    };
+    "bluebird-3.5.1" = {
+      name = "bluebird";
+      packageName = "bluebird";
+      version = "3.5.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz";
+        sha512 = "MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==";
+      };
+    };
+    "brace-expansion-1.1.8" = {
+      name = "brace-expansion";
+      packageName = "brace-expansion";
+      version = "1.1.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz";
+        sha1 = "c07b211c7c952ec1f8efd51a77ef0d1d3990a292";
+      };
+    };
+    "caller-path-0.1.0" = {
+      name = "caller-path";
+      packageName = "caller-path";
+      version = "0.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz";
+        sha1 = "94085ef63581ecd3daa92444a8fe94e82577751f";
+      };
+    };
+    "callsites-0.2.0" = {
+      name = "callsites";
+      packageName = "callsites";
+      version = "0.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz";
+        sha1 = "afab96262910a7f33c19a5775825c69f34e350ca";
+      };
+    };
+    "chalk-1.1.3" = {
+      name = "chalk";
+      packageName = "chalk";
+      version = "1.1.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz";
+        sha1 = "a8115c55e4a702fe4d150abd3872822a7e09fc98";
+      };
+    };
+    "chalk-2.3.0" = {
+      name = "chalk";
+      packageName = "chalk";
+      version = "2.3.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz";
+        sha512 = "Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==";
+      };
+    };
+    "circular-json-0.3.3" = {
+      name = "circular-json";
+      packageName = "circular-json";
+      version = "0.3.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz";
+        sha512 = "UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==";
+      };
+    };
+    "cli-cursor-1.0.2" = {
+      name = "cli-cursor";
+      packageName = "cli-cursor";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz";
+        sha1 = "64da3f7d56a54412e59794bd62dc35295e8f2987";
+      };
+    };
+    "cli-width-1.1.1" = {
+      name = "cli-width";
+      packageName = "cli-width";
+      version = "1.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz";
+        sha1 = "a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d";
+      };
+    };
+    "cli-width-2.2.0" = {
+      name = "cli-width";
+      packageName = "cli-width";
+      version = "2.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz";
+        sha1 = "ff19ede8a9a5e579324147b0c11f0fbcbabed639";
+      };
+    };
+    "co-4.6.0" = {
+      name = "co";
+      packageName = "co";
+      version = "4.6.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/co/-/co-4.6.0.tgz";
+        sha1 = "6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184";
+      };
+    };
+    "code-point-at-1.1.0" = {
+      name = "code-point-at";
+      packageName = "code-point-at";
+      version = "1.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz";
+        sha1 = "0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77";
+      };
+    };
+    "color-convert-1.9.1" = {
+      name = "color-convert";
+      packageName = "color-convert";
+      version = "1.9.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz";
+        sha512 = "mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==";
+      };
+    };
+    "color-name-1.1.3" = {
+      name = "color-name";
+      packageName = "color-name";
+      version = "1.1.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz";
+        sha1 = "a7d0558bd89c42f795dd42328f740831ca53bc25";
+      };
+    };
+    "colors-1.1.2" = {
+      name = "colors";
+      packageName = "colors";
+      version = "1.1.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz";
+        sha1 = "168a4701756b6a7f51a12ce0c97bfa28c084ed63";
+      };
+    };
+    "concat-map-0.0.1" = {
+      name = "concat-map";
+      packageName = "concat-map";
+      version = "0.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz";
+        sha1 = "d8a96bd77fd68df7793a73036a3ba0d5405d477b";
+      };
+    };
+    "concat-stream-1.6.0" = {
+      name = "concat-stream";
+      packageName = "concat-stream";
+      version = "1.6.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz";
+        sha1 = "0aac662fd52be78964d5532f694784e70110acf7";
+      };
+    };
+    "core-js-2.5.3" = {
+      name = "core-js";
+      packageName = "core-js";
+      version = "2.5.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz";
+        sha1 = "8acc38345824f16d8365b7c9b4259168e8ed603e";
+      };
+    };
+    "core-util-is-1.0.2" = {
+      name = "core-util-is";
+      packageName = "core-util-is";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz";
+        sha1 = "b5fd54220aa2bc5ab57aab7140c940754503c1a7";
+      };
+    };
+    "crypto-js-3.1.9-1" = {
+      name = "crypto-js";
+      packageName = "crypto-js";
+      version = "3.1.9-1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz";
+        sha1 = "fda19e761fc077e01ffbfdc6e9fdfc59e8806cd8";
+      };
+    };
+    "d-1.0.0" = {
+      name = "d";
+      packageName = "d";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/d/-/d-1.0.0.tgz";
+        sha1 = "754bb5bfe55451da69a58b94d45f4c5b0462d58f";
+      };
+    };
+    "debug-2.6.9" = {
+      name = "debug";
+      packageName = "debug";
+      version = "2.6.9";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz";
+        sha512 = "bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==";
+      };
+    };
+    "deep-is-0.1.3" = {
+      name = "deep-is";
+      packageName = "deep-is";
+      version = "0.1.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz";
+        sha1 = "b369d6fb5dbc13eecf524f91b070feedc357cf34";
+      };
+    };
+    "del-2.2.2" = {
+      name = "del";
+      packageName = "del";
+      version = "2.2.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/del/-/del-2.2.2.tgz";
+        sha1 = "c12c981d067846c84bcaf862cff930d907ffd1a8";
+      };
+    };
+    "doctrine-2.0.2" = {
+      name = "doctrine";
+      packageName = "doctrine";
+      version = "2.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz";
+        sha512 = "y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==";
+      };
+    };
+    "encoding-0.1.12" = {
+      name = "encoding";
+      packageName = "encoding";
+      version = "0.1.12";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz";
+        sha1 = "538b66f3ee62cd1ab51ec323829d1f9480c74beb";
+      };
+    };
+    "es5-ext-0.10.37" = {
+      name = "es5-ext";
+      packageName = "es5-ext";
+      version = "0.10.37";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.37.tgz";
+        sha1 = "0ee741d148b80069ba27d020393756af257defc3";
+      };
+    };
+    "es6-iterator-2.0.3" = {
+      name = "es6-iterator";
+      packageName = "es6-iterator";
+      version = "2.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz";
+        sha1 = "a7de889141a05a94b0854403b2d0a0fbfa98f3b7";
+      };
+    };
+    "es6-map-0.1.5" = {
+      name = "es6-map";
+      packageName = "es6-map";
+      version = "0.1.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz";
+        sha1 = "9136e0503dcc06a301690f0bb14ff4e364e949f0";
+      };
+    };
+    "es6-set-0.1.5" = {
+      name = "es6-set";
+      packageName = "es6-set";
+      version = "0.1.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz";
+        sha1 = "d2b3ec5d4d800ced818db538d28974db0a73ccb1";
+      };
+    };
+    "es6-symbol-3.1.1" = {
+      name = "es6-symbol";
+      packageName = "es6-symbol";
+      version = "3.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz";
+        sha1 = "bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77";
+      };
+    };
+    "es6-weak-map-2.0.2" = {
+      name = "es6-weak-map";
+      packageName = "es6-weak-map";
+      version = "2.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz";
+        sha1 = "5e3ab32251ffd1538a1f8e5ffa1357772f92d96f";
+      };
+    };
+    "escape-string-regexp-1.0.5" = {
+      name = "escape-string-regexp";
+      packageName = "escape-string-regexp";
+      version = "1.0.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz";
+        sha1 = "1b61c0562190a8dff6ae3bb2cf0200ca130b86d4";
+      };
+    };
+    "escope-3.6.0" = {
+      name = "escope";
+      packageName = "escope";
+      version = "3.6.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz";
+        sha1 = "e01975e812781a163a6dadfdd80398dc64c889c3";
+      };
+    };
+    "eslint-3.19.0" = {
+      name = "eslint";
+      packageName = "eslint";
+      version = "3.19.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz";
+        sha1 = "c8fc6201c7f40dd08941b87c085767386a679acc";
+      };
+    };
+    "espree-3.5.2" = {
+      name = "espree";
+      packageName = "espree";
+      version = "3.5.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz";
+        sha512 = "sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==";
+      };
+    };
+    "esprima-4.0.0" = {
+      name = "esprima";
+      packageName = "esprima";
+      version = "4.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz";
+        sha512 = "oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==";
+      };
+    };
+    "esquery-1.0.0" = {
+      name = "esquery";
+      packageName = "esquery";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz";
+        sha1 = "cfba8b57d7fba93f17298a8a006a04cda13d80fa";
+      };
+    };
+    "esrecurse-4.2.0" = {
+      name = "esrecurse";
+      packageName = "esrecurse";
+      version = "4.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz";
+        sha1 = "fa9568d98d3823f9a41d91e902dcab9ea6e5b163";
+      };
+    };
+    "estraverse-4.2.0" = {
+      name = "estraverse";
+      packageName = "estraverse";
+      version = "4.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz";
+        sha1 = "0dee3fed31fcd469618ce7342099fc1afa0bdb13";
+      };
+    };
+    "esutils-2.0.2" = {
+      name = "esutils";
+      packageName = "esutils";
+      version = "2.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz";
+        sha1 = "0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b";
+      };
+    };
+    "event-emitter-0.3.5" = {
+      name = "event-emitter";
+      packageName = "event-emitter";
+      version = "0.3.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz";
+        sha1 = "df8c69eef1647923c7157b9ce83840610b02cc39";
+      };
+    };
+    "exit-hook-1.1.1" = {
+      name = "exit-hook";
+      packageName = "exit-hook";
+      version = "1.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz";
+        sha1 = "f05ca233b48c05d54fff07765df8507e95c02ff8";
+      };
+    };
+    "fast-levenshtein-2.0.6" = {
+      name = "fast-levenshtein";
+      packageName = "fast-levenshtein";
+      version = "2.0.6";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz";
+        sha1 = "3d8a5c66883a16a30ca8643e851f19baa7797917";
+      };
+    };
+    "figures-1.7.0" = {
+      name = "figures";
+      packageName = "figures";
+      version = "1.7.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz";
+        sha1 = "cbe1e3affcf1cd44b80cadfed28dc793a9701d2e";
+      };
+    };
+    "file-entry-cache-2.0.0" = {
+      name = "file-entry-cache";
+      packageName = "file-entry-cache";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz";
+        sha1 = "c392990c3e684783d838b8c84a45d8a048458361";
+      };
+    };
+    "flat-cache-1.3.0" = {
+      name = "flat-cache";
+      packageName = "flat-cache";
+      version = "1.3.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz";
+        sha1 = "d3030b32b38154f4e3b7e9c709f490f7ef97c481";
+      };
+    };
+    "fs.realpath-1.0.0" = {
+      name = "fs.realpath";
+      packageName = "fs.realpath";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz";
+        sha1 = "1504ad2523158caa40db4a2787cb01411994ea4f";
+      };
+    };
+    "generate-function-2.0.0" = {
+      name = "generate-function";
+      packageName = "generate-function";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz";
+        sha1 = "6858fe7c0969b7d4e9093337647ac79f60dfbe74";
+      };
+    };
+    "generate-object-property-1.2.0" = {
+      name = "generate-object-property";
+      packageName = "generate-object-property";
+      version = "1.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz";
+        sha1 = "9c0e1c40308ce804f4783618b937fa88f99d50d0";
+      };
+    };
+    "glob-7.1.2" = {
+      name = "glob";
+      packageName = "glob";
+      version = "7.1.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz";
+        sha512 = "MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==";
+      };
+    };
+    "globals-9.18.0" = {
+      name = "globals";
+      packageName = "globals";
+      version = "9.18.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz";
+        sha512 = "S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==";
+      };
+    };
+    "globby-5.0.0" = {
+      name = "globby";
+      packageName = "globby";
+      version = "5.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz";
+        sha1 = "ebd84667ca0dbb330b99bcfc68eac2bc54370e0d";
+      };
+    };
+    "graceful-fs-4.1.11" = {
+      name = "graceful-fs";
+      packageName = "graceful-fs";
+      version = "4.1.11";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz";
+        sha1 = "0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658";
+      };
+    };
+    "has-ansi-2.0.0" = {
+      name = "has-ansi";
+      packageName = "has-ansi";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz";
+        sha1 = "34f5049ce1ecdf2b0649af3ef24e45ed35416d91";
+      };
+    };
+    "has-flag-2.0.0" = {
+      name = "has-flag";
+      packageName = "has-flag";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz";
+        sha1 = "e8207af1cc7b30d446cc70b734b5e8be18f88d51";
+      };
+    };
+    "iconv-lite-0.4.19" = {
+      name = "iconv-lite";
+      packageName = "iconv-lite";
+      version = "0.4.19";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz";
+        sha512 = "oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==";
+      };
+    };
+    "ignore-3.3.7" = {
+      name = "ignore";
+      packageName = "ignore";
+      version = "3.3.7";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz";
+        sha512 = "YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==";
+      };
+    };
+    "imurmurhash-0.1.4" = {
+      name = "imurmurhash";
+      packageName = "imurmurhash";
+      version = "0.1.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz";
+        sha1 = "9218b9b2b928a238b13dc4fb6b6d576f231453ea";
+      };
+    };
+    "in-publish-2.0.0" = {
+      name = "in-publish";
+      packageName = "in-publish";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz";
+        sha1 = "e20ff5e3a2afc2690320b6dc552682a9c7fadf51";
+      };
+    };
+    "inflight-1.0.6" = {
+      name = "inflight";
+      packageName = "inflight";
+      version = "1.0.6";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz";
+        sha1 = "49bd6331d7d02d0c09bc910a1075ba8165b56df9";
+      };
+    };
+    "inherits-2.0.3" = {
+      name = "inherits";
+      packageName = "inherits";
+      version = "2.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz";
+        sha1 = "633c2c83e3da42a502f52466022480f4208261de";
+      };
+    };
+    "inquirer-0.11.0" = {
+      name = "inquirer";
+      packageName = "inquirer";
+      version = "0.11.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/inquirer/-/inquirer-0.11.0.tgz";
+        sha1 = "7448bfa924092af311d47173bbab990cae2bb027";
+      };
+    };
+    "inquirer-0.12.0" = {
+      name = "inquirer";
+      packageName = "inquirer";
+      version = "0.12.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz";
+        sha1 = "1ef2bfd63504df0bc75785fff8c2c41df12f077e";
+      };
+    };
+    "install-0.10.4" = {
+      name = "install";
+      packageName = "install";
+      version = "0.10.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/install/-/install-0.10.4.tgz";
+        sha512 = "+IRyOastuPmLVx9zlVXJoKErSqz1Ma5at9A7S8yfsj3W+Kg95faPoh3bPDtMrZ/grz4PRmXzrswmlzfLlYyLOw==";
+      };
+    };
+    "interpret-1.1.0" = {
+      name = "interpret";
+      packageName = "interpret";
+      version = "1.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz";
+        sha1 = "7ed1b1410c6a0e0f78cf95d3b8440c63f78b8614";
+      };
+    };
+    "iota.lib.js-0.4.6" = {
+      name = "iota.lib.js";
+      packageName = "iota.lib.js";
+      version = "0.4.6";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/iota.lib.js/-/iota.lib.js-0.4.6.tgz";
+        sha1 = "47afdc03d57c7f55d2f58f068db492df6bc6e9bb";
+      };
+    };
+    "is-fullwidth-code-point-1.0.0" = {
+      name = "is-fullwidth-code-point";
+      packageName = "is-fullwidth-code-point";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz";
+        sha1 = "ef9e31386f031a7f0d643af82fde50c457ef00cb";
+      };
+    };
+    "is-fullwidth-code-point-2.0.0" = {
+      name = "is-fullwidth-code-point";
+      packageName = "is-fullwidth-code-point";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz";
+        sha1 = "a3b30a5c4f199183167aaab93beefae3ddfb654f";
+      };
+    };
+    "is-my-json-valid-2.16.1" = {
+      name = "is-my-json-valid";
+      packageName = "is-my-json-valid";
+      version = "2.16.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz";
+        sha512 = "ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==";
+      };
+    };
+    "is-path-cwd-1.0.0" = {
+      name = "is-path-cwd";
+      packageName = "is-path-cwd";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz";
+        sha1 = "d225ec23132e89edd38fda767472e62e65f1106d";
+      };
+    };
+    "is-path-in-cwd-1.0.0" = {
+      name = "is-path-in-cwd";
+      packageName = "is-path-in-cwd";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz";
+        sha1 = "6477582b8214d602346094567003be8a9eac04dc";
+      };
+    };
+    "is-path-inside-1.0.1" = {
+      name = "is-path-inside";
+      packageName = "is-path-inside";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz";
+        sha1 = "8ef5b7de50437a3fdca6b4e865ef7aa55cb48036";
+      };
+    };
+    "is-property-1.0.2" = {
+      name = "is-property";
+      packageName = "is-property";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz";
+        sha1 = "57fe1c4e48474edd65b09911f26b1cd4095dda84";
+      };
+    };
+    "is-resolvable-1.0.1" = {
+      name = "is-resolvable";
+      packageName = "is-resolvable";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz";
+        sha512 = "y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==";
+      };
+    };
+    "is-stream-1.1.0" = {
+      name = "is-stream";
+      packageName = "is-stream";
+      version = "1.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz";
+        sha1 = "12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44";
+      };
+    };
+    "isarray-1.0.0" = {
+      name = "isarray";
+      packageName = "isarray";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz";
+        sha1 = "bb935d48582cba168c06834957a54a3e07124f11";
+      };
+    };
+    "js-tokens-3.0.2" = {
+      name = "js-tokens";
+      packageName = "js-tokens";
+      version = "3.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz";
+        sha1 = "9866df395102130e38f7f996bceb65443209c25b";
+      };
+    };
+    "js-yaml-3.10.0" = {
+      name = "js-yaml";
+      packageName = "js-yaml";
+      version = "3.10.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz";
+        sha512 = "O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==";
+      };
+    };
+    "json-stable-stringify-1.0.1" = {
+      name = "json-stable-stringify";
+      packageName = "json-stable-stringify";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz";
+        sha1 = "9a759d39c5f2ff503fd5300646ed445f88c4f9af";
+      };
+    };
+    "json5-0.5.1" = {
+      name = "json5";
+      packageName = "json5";
+      version = "0.5.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz";
+        sha1 = "1eade7acc012034ad84e2396767ead9fa5495821";
+      };
+    };
+    "jsonify-0.0.0" = {
+      name = "jsonify";
+      packageName = "jsonify";
+      version = "0.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz";
+        sha1 = "2c74b6ee41d93ca51b7b5aaee8f503631d252a73";
+      };
+    };
+    "jsonpointer-4.0.1" = {
+      name = "jsonpointer";
+      packageName = "jsonpointer";
+      version = "4.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz";
+        sha1 = "4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9";
+      };
+    };
+    "left-pad-1.2.0" = {
+      name = "left-pad";
+      packageName = "left-pad";
+      version = "1.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/left-pad/-/left-pad-1.2.0.tgz";
+        sha1 = "d30a73c6b8201d8f7d8e7956ba9616087a68e0ee";
+      };
+    };
+    "levn-0.3.0" = {
+      name = "levn";
+      packageName = "levn";
+      version = "0.3.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz";
+        sha1 = "3b09924edf9f083c0490fdd4c0bc4421e04764ee";
+      };
+    };
+    "lodash-3.10.1" = {
+      name = "lodash";
+      packageName = "lodash";
+      version = "3.10.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz";
+        sha1 = "5bf45e8e49ba4189e17d482789dfd15bd140b7b6";
+      };
+    };
+    "lodash-4.17.4" = {
+      name = "lodash";
+      packageName = "lodash";
+      version = "4.17.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz";
+        sha1 = "78203a4d1c328ae1d86dca6460e369b57f4055ae";
+      };
+    };
+    "log-update-1.0.2" = {
+      name = "log-update";
+      packageName = "log-update";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/log-update/-/log-update-1.0.2.tgz";
+        sha1 = "19929f64c4093d2d2e7075a1dad8af59c296b8d1";
+      };
+    };
+    "minimatch-3.0.4" = {
+      name = "minimatch";
+      packageName = "minimatch";
+      version = "3.0.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz";
+        sha512 = "yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==";
+      };
+    };
+    "minimist-0.0.8" = {
+      name = "minimist";
+      packageName = "minimist";
+      version = "0.0.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz";
+        sha1 = "857fcabfc3397d2625b8228262e86aa7a011b05d";
+      };
+    };
+    "minimist-1.2.0" = {
+      name = "minimist";
+      packageName = "minimist";
+      version = "1.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz";
+        sha1 = "a35008b20f41383eec1fb914f4cd5df79a264284";
+      };
+    };
+    "mkdirp-0.5.1" = {
+      name = "mkdirp";
+      packageName = "mkdirp";
+      version = "0.5.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz";
+        sha1 = "30057438eac6cf7f8c4767f38648d6697d75c903";
+      };
+    };
+    "moment-2.20.1" = {
+      name = "moment";
+      packageName = "moment";
+      version = "2.20.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz";
+        sha512 = "Yh9y73JRljxW5QxN08Fner68eFLxM5ynNOAw2LbIB1YAGeQzZT8QFSUvkAz609Zf+IHhhaUxqZK8dG3W/+HEvg==";
+      };
+    };
+    "ms-2.0.0" = {
+      name = "ms";
+      packageName = "ms";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz";
+        sha1 = "5608aeadfc00be6c2901df5f9861788de0d597c8";
+      };
+    };
+    "mute-stream-0.0.5" = {
+      name = "mute-stream";
+      packageName = "mute-stream";
+      version = "0.0.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz";
+        sha1 = "8fbfabb0a98a253d3184331f9e8deb7372fac6c0";
+      };
+    };
+    "natural-compare-1.4.0" = {
+      name = "natural-compare";
+      packageName = "natural-compare";
+      version = "1.4.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz";
+        sha1 = "4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7";
+      };
+    };
+    "node-fetch-1.7.3" = {
+      name = "node-fetch";
+      packageName = "node-fetch";
+      version = "1.7.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz";
+        sha512 = "NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==";
+      };
+    };
+    "node-localstorage-0.6.0" = {
+      name = "node-localstorage";
+      packageName = "node-localstorage";
+      version = "0.6.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/node-localstorage/-/node-localstorage-0.6.0.tgz";
+        sha1 = "45a0601c6932dfde6644a23361f1be173c75d3af";
+      };
+    };
+    "number-is-nan-1.0.1" = {
+      name = "number-is-nan";
+      packageName = "number-is-nan";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz";
+        sha1 = "097b602b53422a522c1afb8790318336941a011d";
+      };
+    };
+    "object-assign-4.1.1" = {
+      name = "object-assign";
+      packageName = "object-assign";
+      version = "4.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz";
+        sha1 = "2109adc7965887cfc05cbbd442cac8bfbb360863";
+      };
+    };
+    "once-1.4.0" = {
+      name = "once";
+      packageName = "once";
+      version = "1.4.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/once/-/once-1.4.0.tgz";
+        sha1 = "583b1aa775961d4b113ac17d9c50baef9dd76bd1";
+      };
+    };
+    "onetime-1.1.0" = {
+      name = "onetime";
+      packageName = "onetime";
+      version = "1.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz";
+        sha1 = "a1f7838f8314c516f05ecefcbc4ccfe04b4ed789";
+      };
+    };
+    "optionator-0.8.2" = {
+      name = "optionator";
+      packageName = "optionator";
+      version = "0.8.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz";
+        sha1 = "364c5e409d3f4d6301d6c0b4c05bba50180aeb64";
+      };
+    };
+    "os-homedir-1.0.2" = {
+      name = "os-homedir";
+      packageName = "os-homedir";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz";
+        sha1 = "ffbc4988336e0e833de0c168c7ef152121aa7fb3";
+      };
+    };
+    "path-is-absolute-1.0.1" = {
+      name = "path-is-absolute";
+      packageName = "path-is-absolute";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz";
+        sha1 = "174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f";
+      };
+    };
+    "path-is-inside-1.0.2" = {
+      name = "path-is-inside";
+      packageName = "path-is-inside";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz";
+        sha1 = "365417dede44430d1c11af61027facf074bdfc53";
+      };
+    };
+    "path-parse-1.0.5" = {
+      name = "path-parse";
+      packageName = "path-parse";
+      version = "1.0.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz";
+        sha1 = "3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1";
+      };
+    };
+    "pify-2.3.0" = {
+      name = "pify";
+      packageName = "pify";
+      version = "2.3.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz";
+        sha1 = "ed141a6ac043a849ea588498e7dca8b15330e90c";
+      };
+    };
+    "pinkie-2.0.4" = {
+      name = "pinkie";
+      packageName = "pinkie";
+      version = "2.0.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz";
+        sha1 = "72556b80cfa0d48a974e80e77248e80ed4f7f870";
+      };
+    };
+    "pinkie-promise-2.0.1" = {
+      name = "pinkie-promise";
+      packageName = "pinkie-promise";
+      version = "2.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz";
+        sha1 = "2135d6dfa7a358c069ac9b178776288228450ffa";
+      };
+    };
+    "pluralize-1.2.1" = {
+      name = "pluralize";
+      packageName = "pluralize";
+      version = "1.2.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz";
+        sha1 = "d1a21483fd22bb41e58a12fa3421823140897c45";
+      };
+    };
+    "prelude-ls-1.1.2" = {
+      name = "prelude-ls";
+      packageName = "prelude-ls";
+      version = "1.1.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz";
+        sha1 = "21932a549f5e52ffd9a827f570e04be62a97da54";
+      };
+    };
+    "prettyjson-1.2.1" = {
+      name = "prettyjson";
+      packageName = "prettyjson";
+      version = "1.2.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/prettyjson/-/prettyjson-1.2.1.tgz";
+        sha1 = "fcffab41d19cab4dfae5e575e64246619b12d289";
+      };
+    };
+    "process-nextick-args-1.0.7" = {
+      name = "process-nextick-args";
+      packageName = "process-nextick-args";
+      version = "1.0.7";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz";
+        sha1 = "150e20b756590ad3f91093f25a4f2ad8bff30ba3";
+      };
+    };
+    "progress-1.1.8" = {
+      name = "progress";
+      packageName = "progress";
+      version = "1.1.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz";
+        sha1 = "e260c78f6161cdd9b0e56cc3e0a85de17c7a57be";
+      };
+    };
+    "readable-stream-2.3.3" = {
+      name = "readable-stream";
+      packageName = "readable-stream";
+      version = "2.3.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz";
+        sha512 = "m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==";
+      };
+    };
+    "readline2-1.0.1" = {
+      name = "readline2";
+      packageName = "readline2";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz";
+        sha1 = "41059608ffc154757b715d9989d199ffbf372e35";
+      };
+    };
+    "rechoir-0.6.2" = {
+      name = "rechoir";
+      packageName = "rechoir";
+      version = "0.6.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz";
+        sha1 = "85204b54dba82d5742e28c96756ef43af50e3384";
+      };
+    };
+    "regenerator-runtime-0.10.5" = {
+      name = "regenerator-runtime";
+      packageName = "regenerator-runtime";
+      version = "0.10.5";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz";
+        sha1 = "336c3efc1220adcedda2c9fab67b5a7955a33658";
+      };
+    };
+    "regenerator-runtime-0.11.1" = {
+      name = "regenerator-runtime";
+      packageName = "regenerator-runtime";
+      version = "0.11.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz";
+        sha512 = "MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==";
+      };
+    };
+    "require-uncached-1.0.3" = {
+      name = "require-uncached";
+      packageName = "require-uncached";
+      version = "1.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz";
+        sha1 = "4e0d56d6c9662fd31e43011c4b95aa49955421d3";
+      };
+    };
+    "resolve-1.5.0" = {
+      name = "resolve";
+      packageName = "resolve";
+      version = "1.5.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz";
+        sha512 = "hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==";
+      };
+    };
+    "resolve-from-1.0.1" = {
+      name = "resolve-from";
+      packageName = "resolve-from";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz";
+        sha1 = "26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226";
+      };
+    };
+    "restore-cursor-1.0.1" = {
+      name = "restore-cursor";
+      packageName = "restore-cursor";
+      version = "1.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz";
+        sha1 = "34661f46886327fed2991479152252df92daa541";
+      };
+    };
+    "rimraf-2.6.2" = {
+      name = "rimraf";
+      packageName = "rimraf";
+      version = "2.6.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz";
+        sha512 = "lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==";
+      };
+    };
+    "run-async-0.1.0" = {
+      name = "run-async";
+      packageName = "run-async";
+      version = "0.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz";
+        sha1 = "c8ad4a5e110661e402a7d21b530e009f25f8e389";
+      };
+    };
+    "rx-lite-3.1.2" = {
+      name = "rx-lite";
+      packageName = "rx-lite";
+      version = "3.1.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz";
+        sha1 = "19ce502ca572665f3b647b10939f97fd1615f102";
+      };
+    };
+    "safe-buffer-5.1.1" = {
+      name = "safe-buffer";
+      packageName = "safe-buffer";
+      version = "5.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz";
+        sha512 = "kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==";
+      };
+    };
+    "shelljs-0.7.8" = {
+      name = "shelljs";
+      packageName = "shelljs";
+      version = "0.7.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz";
+        sha1 = "decbcf874b0d1e5fb72e14b164a9683048e9acb3";
+      };
+    };
+    "slice-ansi-0.0.4" = {
+      name = "slice-ansi";
+      packageName = "slice-ansi";
+      version = "0.0.4";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz";
+        sha1 = "edbf8903f66f7ce2f8eafd6ceed65e264c831b35";
+      };
+    };
+    "sprintf-js-1.0.3" = {
+      name = "sprintf-js";
+      packageName = "sprintf-js";
+      version = "1.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz";
+        sha1 = "04e6926f662895354f3dd015203633b857297e2c";
+      };
+    };
+    "string-width-1.0.2" = {
+      name = "string-width";
+      packageName = "string-width";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz";
+        sha1 = "118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3";
+      };
+    };
+    "string-width-2.1.1" = {
+      name = "string-width";
+      packageName = "string-width";
+      version = "2.1.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz";
+        sha512 = "nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==";
+      };
+    };
+    "string_decoder-1.0.3" = {
+      name = "string_decoder";
+      packageName = "string_decoder";
+      version = "1.0.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz";
+        sha512 = "4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==";
+      };
+    };
+    "strip-ansi-3.0.1" = {
+      name = "strip-ansi";
+      packageName = "strip-ansi";
+      version = "3.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz";
+        sha1 = "6a385fb8853d952d5ff05d0e8aaf94278dc63dcf";
+      };
+    };
+    "strip-ansi-4.0.0" = {
+      name = "strip-ansi";
+      packageName = "strip-ansi";
+      version = "4.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz";
+        sha1 = "a8479022eb1ac368a871389b635262c505ee368f";
+      };
+    };
+    "strip-bom-3.0.0" = {
+      name = "strip-bom";
+      packageName = "strip-bom";
+      version = "3.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz";
+        sha1 = "2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3";
+      };
+    };
+    "strip-json-comments-2.0.1" = {
+      name = "strip-json-comments";
+      packageName = "strip-json-comments";
+      version = "2.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz";
+        sha1 = "3c531942e908c2697c0ec344858c286c7ca0a60a";
+      };
+    };
+    "supports-color-2.0.0" = {
+      name = "supports-color";
+      packageName = "supports-color";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz";
+        sha1 = "535d045ce6b6363fa40117084629995e9df324c7";
+      };
+    };
+    "supports-color-4.5.0" = {
+      name = "supports-color";
+      packageName = "supports-color";
+      version = "4.5.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz";
+        sha1 = "be7a0de484dec5c5cddf8b3d59125044912f635b";
+      };
+    };
+    "table-3.8.3" = {
+      name = "table";
+      packageName = "table";
+      version = "3.8.3";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/table/-/table-3.8.3.tgz";
+        sha1 = "2bbc542f0fda9861a755d3947fefd8b3f513855f";
+      };
+    };
+    "text-table-0.2.0" = {
+      name = "text-table";
+      packageName = "text-table";
+      version = "0.2.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz";
+        sha1 = "7f5ee823ae805207c00af2df4a84ec3fcfa570b4";
+      };
+    };
+    "through-2.3.8" = {
+      name = "through";
+      packageName = "through";
+      version = "2.3.8";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/through/-/through-2.3.8.tgz";
+        sha1 = "0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5";
+      };
+    };
+    "type-check-0.3.2" = {
+      name = "type-check";
+      packageName = "type-check";
+      version = "0.3.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz";
+        sha1 = "5884cab512cf1d355e3fb784f30804b2b520db72";
+      };
+    };
+    "typedarray-0.0.6" = {
+      name = "typedarray";
+      packageName = "typedarray";
+      version = "0.0.6";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz";
+        sha1 = "867ac74e3864187b1d3d47d996a78ec5c8830777";
+      };
+    };
+    "user-home-2.0.0" = {
+      name = "user-home";
+      packageName = "user-home";
+      version = "2.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz";
+        sha1 = "9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f";
+      };
+    };
+    "util-deprecate-1.0.2" = {
+      name = "util-deprecate";
+      packageName = "util-deprecate";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz";
+        sha1 = "450d4dc9fa70de732762fbd2d4a28981419a0ccf";
+      };
+    };
+    "vorpal-1.12.0" = {
+      name = "vorpal";
+      packageName = "vorpal";
+      version = "1.12.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/vorpal/-/vorpal-1.12.0.tgz";
+        sha1 = "4be7b2a4e48f8fcfc9cf3648c419d311c522159d";
+      };
+    };
+    "wordwrap-1.0.0" = {
+      name = "wordwrap";
+      packageName = "wordwrap";
+      version = "1.0.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz";
+        sha1 = "27584810891456a4171c8d0226441ade90cbcaeb";
+      };
+    };
+    "wrap-ansi-2.1.0" = {
+      name = "wrap-ansi";
+      packageName = "wrap-ansi";
+      version = "2.1.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz";
+        sha1 = "d8fc3d284dd05794fe84973caecdd1cf824fdd85";
+      };
+    };
+    "wrappy-1.0.2" = {
+      name = "wrappy";
+      packageName = "wrappy";
+      version = "1.0.2";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz";
+        sha1 = "b5243d8f3ec1aa35f1364605bc0d1036e30ab69f";
+      };
+    };
+    "write-0.2.1" = {
+      name = "write";
+      packageName = "write";
+      version = "0.2.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/write/-/write-0.2.1.tgz";
+        sha1 = "5fc03828e264cea3fe91455476f7a3c566cb0757";
+      };
+    };
+    "xmlhttprequest-1.8.0" = {
+      name = "xmlhttprequest";
+      packageName = "xmlhttprequest";
+      version = "1.8.0";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz";
+        sha1 = "67fe075c5c24fef39f9d65f5f7b7fe75171968fc";
+      };
+    };
+    "xtend-4.0.1" = {
+      name = "xtend";
+      packageName = "xtend";
+      version = "4.0.1";
+      src = fetchurl {
+        url = "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz";
+        sha1 = "a5c6d532be656e23db820efb943a1f04998d63af";
+      };
+    };
+  };
+  args = {
+    name = "iota-cli-app";
+    packageName = "iota-cli-app";
+    version = "1.0.8";
+    inherit src;
+    dependencies = [
+      sources."acorn-5.2.1"
+      (sources."acorn-jsx-3.0.1" // {
+        dependencies = [
+          sources."acorn-3.3.0"
+        ];
+      })
+      sources."ajv-4.11.8"
+      sources."ajv-keywords-1.5.1"
+      sources."ansi-escapes-1.4.0"
+      sources."ansi-regex-2.1.1"
+      sources."ansi-styles-3.2.0"
+      sources."argparse-1.0.9"
+      sources."array-union-1.0.2"
+      sources."array-uniq-1.0.3"
+      sources."arrify-1.0.1"
+      sources."async-2.6.0"
+      (sources."babel-code-frame-6.26.0" // {
+        dependencies = [
+          sources."ansi-styles-2.2.1"
+          sources."chalk-1.1.3"
+          sources."supports-color-2.0.0"
+        ];
+      })
+      sources."babel-polyfill-6.26.0"
+      (sources."babel-runtime-6.26.0" // {
+        dependencies = [
+          sources."regenerator-runtime-0.11.1"
+        ];
+      })
+      sources."balanced-match-1.0.0"
+      sources."bignumber.js-4.1.0"
+      sources."bluebird-3.5.1"
+      sources."brace-expansion-1.1.8"
+      sources."caller-path-0.1.0"
+      sources."callsites-0.2.0"
+      sources."chalk-2.3.0"
+      sources."circular-json-0.3.3"
+      sources."cli-cursor-1.0.2"
+      sources."cli-width-2.2.0"
+      sources."co-4.6.0"
+      sources."code-point-at-1.1.0"
+      sources."color-convert-1.9.1"
+      sources."color-name-1.1.3"
+      sources."colors-1.1.2"
+      sources."concat-map-0.0.1"
+      sources."concat-stream-1.6.0"
+      sources."core-js-2.5.3"
+      sources."core-util-is-1.0.2"
+      sources."crypto-js-3.1.9-1"
+      sources."d-1.0.0"
+      sources."debug-2.6.9"
+      sources."deep-is-0.1.3"
+      sources."del-2.2.2"
+      sources."doctrine-2.0.2"
+      sources."encoding-0.1.12"
+      sources."es5-ext-0.10.37"
+      sources."es6-iterator-2.0.3"
+      sources."es6-map-0.1.5"
+      sources."es6-set-0.1.5"
+      sources."es6-symbol-3.1.1"
+      sources."es6-weak-map-2.0.2"
+      sources."escape-string-regexp-1.0.5"
+      sources."escope-3.6.0"
+      (sources."eslint-3.19.0" // {
+        dependencies = [
+          sources."ansi-styles-2.2.1"
+          sources."chalk-1.1.3"
+          sources."supports-color-2.0.0"
+        ];
+      })
+      sources."espree-3.5.2"
+      sources."esprima-4.0.0"
+      sources."esquery-1.0.0"
+      sources."esrecurse-4.2.0"
+      sources."estraverse-4.2.0"
+      sources."esutils-2.0.2"
+      sources."event-emitter-0.3.5"
+      sources."exit-hook-1.1.1"
+      sources."fast-levenshtein-2.0.6"
+      sources."figures-1.7.0"
+      sources."file-entry-cache-2.0.0"
+      sources."flat-cache-1.3.0"
+      sources."fs.realpath-1.0.