From 102240a4ef9d86b4775f0b5c9d97b66b0b2c091a Mon Sep 17 00:00:00 2001 From: Ivan Udovichenko Date: Tue, 27 Mar 2018 13:58:36 +0000 Subject: [PATCH] Revert "Update rabbitmq-server packages" This reverts commit e0b39639de0389b8d2307436c2b3eb34fa86a735. Change-Id: Id5270ae980ffac91e96e5ee83b29dbc3bea67a69 Downgrade-due: https://mirantis.jira.com/browse/PROD-18846 --- .gitignore | 1 + .../CODE_OF_CONDUCT.md => CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md => CONTRIBUTING.md | 0 rabbitmq-server/LICENSE => LICENSE | 0 ...erCanvas => LICENSE-APACHE2-ExplorerCanvas | 0 .../LICENSE-APL2-Rebar => LICENSE-APL2-Rebar | 0 ...-Websocket => LICENSE-APL2-Stomp-Websocket | 0 ...CENSE-BSD-base64js => LICENSE-BSD-base64js | 0 ...CENSE-BSD-glMatrix => LICENSE-BSD-glMatrix | 0 .../LICENSE-EPL-OTP => LICENSE-EPL-OTP | 0 .../LICENSE-MIT-EJS10 => LICENSE-MIT-EJS10 | 0 ...are-Commons => LICENSE-MIT-Erlware-Commons | 0 .../LICENSE-MIT-Flot => LICENSE-MIT-Flot | 0 .../LICENSE-MIT-Mochi => LICENSE-MIT-Mochi | 0 ...CENSE-MIT-Mochiweb => LICENSE-MIT-Mochiweb | 0 ...CENSE-MIT-Sammy060 => LICENSE-MIT-Sammy060 | 0 .../LICENSE-MIT-SockJS => LICENSE-MIT-SockJS | 0 ...NSE-MIT-jQuery164 => LICENSE-MIT-jQuery164 | 0 ...CENSE-MPL-RabbitMQ => LICENSE-MPL-RabbitMQ | 0 rabbitmq-server/LICENSE-MPL2 => LICENSE-MPL2 | 0 rabbitmq-server/Makefile => Makefile | 113 +- debian/changelog | 550 +- debian/control | 49 +- debian/copyright | 603 +- debian/dirs | 9 + debian/gbp.conf | 11 - debian/patches/native-code-location.patch | 10 + debian/patches/series | 1 + debian/postinst | 63 + debian/postrm.in | 65 + debian/rabbitmq-env.conf | 13 - debian/rabbitmq-script-wrapper | 47 - debian/rabbitmq-server-wait | 22 - debian/rabbitmq-server.default | 1 - debian/rabbitmq-server.dirs | 3 - debian/rabbitmq-server.docs | 2 + debian/rabbitmq-server.init | 25 +- debian/rabbitmq-server.install | 4 - debian/rabbitmq-server.links | 3 - debian/rabbitmq-server.manpages | 4 + debian/rabbitmq-server.postinst | 45 - debian/rabbitmq-server.postrm | 30 - debian/rabbitmq-server.service | 19 +- debian/rules | 50 +- debian/source.lintian-overrides | 3 - debian/watch | 4 +- .../amqp_client/CODE_OF_CONDUCT.md | 0 .../deps => deps}/amqp_client/CONTRIBUTING.md | 0 .../deps => deps}/amqp_client/Makefile | 69 +- .../deps => deps}/amqp_client/README.in | 0 .../deps => deps}/amqp_client/ci/test.sh | 0 .../deps => deps}/amqp_client/ci/test.yml | 0 .../deps/ranch => deps/amqp_client}/erlang.mk | 765 +- .../amqp_client/include/amqp_client.hrl | 0 .../include/amqp_client_internal.hrl | 0 .../include/amqp_gen_consumer_spec.hrl | 0 .../include/rabbit_routing_prefixes.hrl | 0 .../amqp_client}/rabbitmq-components.mk | 62 +- .../amqp_client/src/amqp_auth_mechanisms.erl | 2 +- .../amqp_client/src/amqp_channel.erl | 31 +- .../amqp_client/src/amqp_channel_sup.erl | 2 +- .../amqp_client/src/amqp_channel_sup_sup.erl | 4 +- .../amqp_client/src/amqp_channels_manager.erl | 8 +- deps/amqp_client/src/amqp_client.app.src | 9 + .../amqp_client/src/amqp_client.erl | 9 +- .../amqp_client/src/amqp_connection.erl | 11 +- .../amqp_client/src/amqp_connection_sup.erl | 2 +- .../src/amqp_connection_type_sup.erl | 2 +- .../src/amqp_direct_connection.erl | 12 +- .../amqp_client/src/amqp_direct_consumer.erl | 0 .../amqp_client/src/amqp_gen_connection.erl | 13 +- .../amqp_client/src/amqp_gen_consumer.erl | 0 .../amqp_client/src/amqp_main_reader.erl | 2 +- .../src/amqp_network_connection.erl | 11 +- .../amqp_client/src/amqp_rpc_client.erl | 2 +- .../amqp_client/src/amqp_rpc_server.erl | 2 +- .../src/amqp_selective_consumer.erl | 0 .../amqp_client/src/amqp_sup.erl | 2 +- .../amqp_client/src/amqp_uri.erl | 17 +- .../amqp_client/src/overview.edoc.in | 0 .../amqp_client/src/rabbit_routing_util.erl | 0 .../amqp_client/src/uri_parser.erl | 4 +- {rabbitmq-server/deps => deps}/cowboy/AUTHORS | 0 .../deps => deps}/cowboy/CHANGELOG.md | 5 - .../deps => deps}/cowboy/CONTRIBUTING.md | 0 {rabbitmq-server/deps => deps}/cowboy/LICENSE | 0 .../deps => deps}/cowboy/Makefile | 2 +- .../deps => deps}/cowboy/README.md | 0 .../deps => deps}/cowboy/ROADMAP.md | 0 {rabbitmq-server/deps => deps}/cowboy/all.sh | 0 .../deps => deps}/cowboy/circle.yml | 1 - deps/cowboy/erlang.mk | 1 + .../deps => deps}/cowboy/rebar.config | 0 .../deps => deps}/cowboy/src/cowboy.app.src | 2 +- .../deps => deps}/cowboy/src/cowboy.erl | 0 .../deps => deps}/cowboy/src/cowboy_app.erl | 0 .../deps => deps}/cowboy/src/cowboy_bstr.erl | 0 .../deps => deps}/cowboy/src/cowboy_clock.erl | 0 .../cowboy/src/cowboy_handler.erl | 0 .../deps => deps}/cowboy/src/cowboy_http.erl | 0 .../cowboy/src/cowboy_http_handler.erl | 0 .../cowboy/src/cowboy_loop_handler.erl | 0 .../cowboy/src/cowboy_middleware.erl | 0 .../cowboy/src/cowboy_protocol.erl | 0 .../deps => deps}/cowboy/src/cowboy_req.erl | 0 .../deps => deps}/cowboy/src/cowboy_rest.erl | 0 .../cowboy/src/cowboy_router.erl | 0 .../deps => deps}/cowboy/src/cowboy_spdy.erl | 0 .../cowboy/src/cowboy_static.erl | 0 .../cowboy/src/cowboy_sub_protocol.erl | 0 .../deps => deps}/cowboy/src/cowboy_sup.erl | 0 .../cowboy/src/cowboy_websocket.erl | 2 +- .../cowboy/src/cowboy_websocket_handler.erl | 0 {rabbitmq-server/deps => deps}/cowlib/AUTHORS | 1 - .../deps => deps}/cowlib/CHANGELOG.md | 5 - {rabbitmq-server/deps => deps}/cowlib/LICENSE | 0 .../deps => deps}/cowlib/Makefile | 5 +- .../deps => deps}/cowlib/README.md | 0 deps/cowlib/all.sh | 17 + deps/cowlib/build.config | 20 + deps/cowlib/erlang.mk | 1 + .../cowlib/include/cow_inline.hrl | 0 .../deps => deps}/cowlib/src/cow_cookie.erl | 8 - .../deps => deps}/cowlib/src/cow_date.erl | 0 .../deps => deps}/cowlib/src/cow_http.erl | 0 .../deps => deps}/cowlib/src/cow_http_hd.erl | 0 .../deps => deps}/cowlib/src/cow_http_te.erl | 0 .../cowlib/src/cow_mimetypes.erl | 0 .../cowlib/src/cow_mimetypes.erl.src | 0 .../cowlib/src/cow_multipart.erl | 0 .../deps => deps}/cowlib/src/cow_qs.erl | 0 .../deps => deps}/cowlib/src/cow_spdy.erl | 0 .../deps => deps}/cowlib/src/cow_spdy.hrl | 0 .../deps => deps}/cowlib/src/cowlib.app.src | 2 +- .../licensing/LICENSE-APACHE2-ExplorerCanvas | 0 .../licensing/LICENSE-APL2-Rebar | 0 .../licensing/LICENSE-APL2-Stomp-Websocket | 0 .../licensing/LICENSE-BSD-base64js | 0 .../licensing/LICENSE-BSD-glMatrix | 0 .../deps => deps}/licensing/LICENSE-EPL-OTP | 0 .../deps => deps}/licensing/LICENSE-MIT-EJS10 | 0 .../licensing/LICENSE-MIT-Erlware-Commons | 0 .../deps => deps}/licensing/LICENSE-MIT-Flot | 0 .../deps => deps}/licensing/LICENSE-MIT-Mochi | 0 .../licensing/LICENSE-MIT-Mochiweb | 0 .../licensing/LICENSE-MIT-Sammy060 | 0 .../licensing/LICENSE-MIT-SockJS | 0 .../licensing/LICENSE-MIT-jQuery164 | 0 .../licensing/LICENSE-MPL-RabbitMQ | 0 .../deps => deps}/licensing/LICENSE-MPL2 | 0 .../licensing/license_info_rabbitmq_codegen | 0 .../license_info_rabbitmq_management | 0 ...icense_info_rabbitmq_management_visualiser | 0 deps/mochiweb/.editorconfig | 17 + deps/mochiweb/CHANGES.md | 206 + .../mochiweb/LICENSE | 0 deps/mochiweb/Makefile | 22 + deps/mochiweb/Makefile.orig.mk | 24 + deps/mochiweb/README | 17 + deps/mochiweb/examples/hmac_api/README | 206 + deps/mochiweb/examples/hmac_api/hmac_api.hrl | 43 + .../examples/hmac_api/hmac_api_client.erl | 34 + .../examples/hmac_api/hmac_api_lib.erl | 435 ++ deps/mochiweb/examples/https/https_store.erl | 146 + deps/mochiweb/examples/https/server_cert.pem | 19 + deps/mochiweb/examples/https/server_key.pem | 27 + .../mochiweb/examples/keepalive/keepalive.erl | 81 + deps/mochiweb/examples/websocket/index.html | 59 + .../mochiweb/examples/websocket/websocket.erl | 148 + deps/mochiweb/include/internal.hrl | 3 + deps/mochiweb/rebar | Bin 0 -> 159782 bytes deps/mochiweb/rebar.config | 17 + deps/mochiweb/scripts/entities.erl | 45 + deps/mochiweb/src/mochifmt.erl | 443 ++ deps/mochiweb/src/mochifmt_records.erl | 60 + deps/mochiweb/src/mochifmt_std.erl | 51 + deps/mochiweb/src/mochiglobal.erl | 127 + deps/mochiweb/src/mochihex.erl | 106 + deps/mochiweb/src/mochijson.erl | 547 ++ deps/mochiweb/src/mochijson2.erl | 942 +++ deps/mochiweb/src/mochilists.erl | 122 + deps/mochiweb/src/mochilogfile2.erl | 158 + deps/mochiweb/src/mochinum.erl | 372 + deps/mochiweb/src/mochitemp.erl | 329 + deps/mochiweb/src/mochiutf8.erl | 335 + deps/mochiweb/src/mochiweb.app.src | 8 + deps/mochiweb/src/mochiweb.erl | 101 + deps/mochiweb/src/mochiweb_acceptor.erl | 83 + deps/mochiweb/src/mochiweb_base64url.erl | 105 + deps/mochiweb/src/mochiweb_charref.erl | 2201 ++++++ deps/mochiweb/src/mochiweb_clock.erl | 101 + deps/mochiweb/src/mochiweb_cookies.erl | 349 + deps/mochiweb/src/mochiweb_cover.erl | 93 + deps/mochiweb/src/mochiweb_echo.erl | 59 + deps/mochiweb/src/mochiweb_headers.erl | 438 ++ deps/mochiweb/src/mochiweb_html.erl | 815 ++ deps/mochiweb/src/mochiweb_http.erl | 307 + deps/mochiweb/src/mochiweb_io.erl | 61 + deps/mochiweb/src/mochiweb_mime.erl | 433 + deps/mochiweb/src/mochiweb_multipart.erl | 890 +++ deps/mochiweb/src/mochiweb_request.erl | 904 +++ deps/mochiweb/src/mochiweb_response.erl | 90 + deps/mochiweb/src/mochiweb_session.erl | 229 + deps/mochiweb/src/mochiweb_socket.erl | 148 + deps/mochiweb/src/mochiweb_socket_server.erl | 394 + .../mochiweb}/src/mochiweb_util.erl | 50 +- deps/mochiweb/src/mochiweb_websocket.erl | 281 + deps/mochiweb/src/reloader.erl | 179 + .../support/templates/mochiwebapp.template | 24 + .../templates/mochiwebapp_skel/bench.sh | 19 + .../mochiwebapp_skel/priv/www/index.html | 8 + .../templates/mochiwebapp_skel/rebar.config | 7 + .../mochiwebapp_skel/src/mochiapp.app.src | 9 + .../mochiwebapp_skel/src/mochiapp.erl | 30 + .../mochiwebapp_skel/src/mochiapp_app.erl | 22 + .../mochiwebapp_skel/src/mochiapp_deps.erl | 84 + .../mochiwebapp_skel/src/mochiapp_sup.erl | 56 + .../mochiwebapp_skel/src/mochiapp_web.erl | 71 + .../templates/mochiwebapp_skel/start-dev.sh | 7 + .../support/test-materials/test_ssl_cert.pem | 19 + .../support/test-materials/test_ssl_key.pem | 27 + .../deps => deps}/rabbit/CODE_OF_CONDUCT.md | 0 .../rabbit}/CONTRIBUTING.md | 0 {rabbitmq-server/deps => deps}/rabbit/INSTALL | 0 {rabbitmq-server/deps => deps}/rabbit/LICENSE | 0 deps/rabbit/LICENSE-MIT-Mochi | 9 + .../deps => deps}/rabbit/LICENSE-MPL-RabbitMQ | 0 deps/rabbit/Makefile | 118 + deps/rabbit/README | 1 + .../deps => deps}/rabbit/README.md | 2 +- .../deps => deps}/rabbit/check_xref | 0 .../rabbit/docs/README-for-packages | 0 .../rabbit/docs/examples-to-end.xsl | 0 .../rabbit/docs/html-to-website-xml.xsl | 0 .../rabbit/docs/rabbitmq-echopid.xml | 0 .../rabbit/docs/rabbitmq-env.conf.5.xml | 0 .../rabbit/docs/rabbitmq-plugins.1.xml | 0 .../rabbit/docs/rabbitmq-server.1.xml | 0 .../docs/rabbitmq-server.service.example | 0 .../rabbit/docs/rabbitmq-service.xml | 0 .../rabbit/docs/rabbitmq.config.example | 35 +- .../rabbit/docs/rabbitmqctl.1.xml | 186 +- .../rabbit/docs/remove-namespaces.xsl | 0 .../docs/set_rabbitmq_policy.sh.example | 0 .../deps => deps}/rabbit/docs/usage.xsl | 0 .../rabbit_common => deps/rabbit}/erlang.mk | 1129 ++- .../deps => deps}/rabbit/include/gm_specs.hrl | 2 +- .../rabbit/include/rabbit_cli.hrl | 2 +- .../deps => deps}/rabbit/quickcheck | 0 .../rabbit/rabbitmq-components.mk | 62 +- .../rabbit/scripts/rabbitmq-defaults | 11 - .../rabbit/scripts/rabbitmq-defaults.bat | 0 .../rabbit/scripts/rabbitmq-echopid.bat | 0 .../deps => deps}/rabbit/scripts/rabbitmq-env | 25 +- .../rabbit/scripts/rabbitmq-env.bat | 11 +- .../rabbit/scripts/rabbitmq-plugins | 0 .../rabbit/scripts/rabbitmq-plugins.bat | 0 .../rabbit/scripts/rabbitmq-server | 49 +- .../rabbit/scripts/rabbitmq-server.bat | 12 +- .../rabbit/scripts/rabbitmq-service.bat | 28 +- .../deps => deps}/rabbit/scripts/rabbitmqctl | 0 .../rabbit/scripts/rabbitmqctl.bat | 0 .../rabbit/src/background_gc.erl | 23 +- .../rabbit}/src/delegate.erl | 104 +- .../rabbit}/src/delegate_sup.erl | 31 +- .../deps => deps}/rabbit/src/dtree.erl | 2 +- .../rabbit}/src/file_handle_cache.erl | 38 +- .../rabbit}/src/file_handle_cache_stats.erl | 2 +- .../deps => deps}/rabbit/src/gatherer.erl | 2 +- .../deps => deps}/rabbit/src/gm.erl | 36 +- .../deps => deps}/rabbit/src/lqueue.erl | 0 .../rabbit/src/mirrored_supervisor_sups.erl | 0 .../rabbit}/src/mnesia_sync.erl | 2 +- .../deps => deps}/rabbit/src/pg_local.erl | 0 deps/rabbit/src/rabbit.app.src | 111 + .../deps => deps}/rabbit/src/rabbit.erl | 137 +- .../rabbit/src/rabbit_access_control.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_alarm.erl | 14 +- .../rabbit/src/rabbit_amqqueue_process.erl | 34 +- .../rabbit/src/rabbit_amqqueue_sup.erl | 2 +- .../rabbit/src/rabbit_amqqueue_sup_sup.erl | 2 +- .../src/rabbit_auth_mechanism_amqplain.erl | 2 +- .../src/rabbit_auth_mechanism_cr_demo.erl | 2 +- .../src/rabbit_auth_mechanism_plain.erl | 2 +- .../rabbit/src/rabbit_autoheal.erl | 2 +- .../rabbit/src/rabbit_binding.erl | 2 +- .../rabbit/src/rabbit_boot_steps.erl | 0 .../rabbit/src/rabbit_channel_sup.erl | 2 +- .../rabbit/src/rabbit_channel_sup_sup.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_cli.erl | 6 +- .../rabbit/src/rabbit_client_sup.erl | 2 +- .../src/rabbit_connection_helper_sup.erl | 2 +- .../rabbit/src/rabbit_connection_sup.erl | 2 +- .../rabbit/src/rabbit_control_main.erl | 110 +- deps/rabbit/src/rabbit_control_pbe.erl | 79 + .../rabbit/src/rabbit_dead_letter.erl | 2 +- .../rabbit/src/rabbit_diagnostics.erl | 3 +- .../rabbit/src/rabbit_direct.erl | 4 +- .../rabbit/src/rabbit_disk_monitor.erl | 51 +- .../rabbit/src/rabbit_epmd_monitor.erl | 4 +- .../rabbit/src/rabbit_error_logger.erl | 2 +- .../rabbit/src/rabbit_error_logger_file_h.erl | 2 +- .../rabbit/src/rabbit_exchange.erl | 7 +- .../rabbit/src/rabbit_exchange_parameters.erl | 2 +- .../src/rabbit_exchange_type_direct.erl | 2 +- .../src/rabbit_exchange_type_fanout.erl | 2 +- .../src/rabbit_exchange_type_headers.erl | 2 +- .../src/rabbit_exchange_type_invalid.erl | 2 +- .../rabbit/src/rabbit_exchange_type_topic.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_file.erl | 0 .../rabbit/src/rabbit_framing.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_guid.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_hipe.erl | 0 .../rabbit/src/rabbit_limiter.erl | 2 +- .../rabbit}/src/rabbit_log.erl | 27 +- .../rabbit/src/rabbit_memory_monitor.erl | 16 +- .../src/rabbit_mirror_queue_coordinator.erl | 0 .../rabbit/src/rabbit_mirror_queue_master.erl | 0 .../rabbit/src/rabbit_mirror_queue_misc.erl | 0 .../rabbit/src/rabbit_mirror_queue_mode.erl | 0 .../src/rabbit_mirror_queue_mode_all.erl | 0 .../src/rabbit_mirror_queue_mode_exactly.erl | 0 .../src/rabbit_mirror_queue_mode_nodes.erl | 0 .../rabbit/src/rabbit_mirror_queue_slave.erl | 0 .../rabbit/src/rabbit_mirror_queue_sync.erl | 4 +- .../rabbit/src/rabbit_mnesia.erl | 38 +- .../rabbit/src/rabbit_mnesia_rename.erl | 4 +- .../rabbit/src/rabbit_msg_file.erl | 2 +- .../rabbit/src/rabbit_msg_store.erl | 10 +- .../rabbit/src/rabbit_msg_store_ets_index.erl | 2 +- .../rabbit/src/rabbit_msg_store_gc.erl | 2 +- .../rabbit/src/rabbit_node_monitor.erl | 42 +- .../src/rabbit_parameter_validation.erl | 2 +- .../rabbit/src/rabbit_password.erl | 2 +- .../src/rabbit_password_hashing_md5.erl | 2 +- .../src/rabbit_password_hashing_sha256.erl | 2 +- .../src/rabbit_password_hashing_sha512.erl | 2 +- .../rabbit}/src/rabbit_pbe.erl | 18 +- .../rabbit/src/rabbit_plugins.erl | 224 +- .../rabbit/src/rabbit_plugins_main.erl | 39 +- .../rabbit/src/rabbit_policies.erl | 2 +- .../rabbit/src/rabbit_policy.erl | 2 +- .../rabbit/src/rabbit_prelaunch.erl | 2 +- .../rabbit/src/rabbit_prequeue.erl | 0 .../rabbit/src/rabbit_priority_queue.erl | 2 +- .../rabbit/src/rabbit_queue_consumers.erl | 2 +- .../rabbit/src/rabbit_queue_index.erl | 47 +- .../rabbit_queue_location_client_local.erl | 2 +- .../src/rabbit_queue_location_min_masters.erl | 2 +- .../src/rabbit_queue_location_random.erl | 2 +- .../src/rabbit_queue_location_validator.erl | 2 +- .../src/rabbit_queue_master_location_misc.erl | 6 +- .../rabbit/src/rabbit_recovery_terms.erl | 2 +- .../rabbit/src/rabbit_registry.erl | 2 +- .../src/rabbit_resource_monitor_misc.erl | 2 +- .../rabbit/src/rabbit_restartable_sup.erl | 2 +- .../rabbit/src/rabbit_router.erl | 2 +- .../rabbit/src/rabbit_runtime_parameters.erl | 95 +- .../rabbit/src/rabbit_sasl_report_file_h.erl | 2 +- .../rabbit/src/rabbit_ssl.erl | 70 +- .../deps => deps}/rabbit/src/rabbit_sup.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_table.erl | 70 +- .../deps => deps}/rabbit/src/rabbit_trace.erl | 2 +- .../rabbit/src/rabbit_upgrade.erl | 2 +- .../rabbit/src/rabbit_upgrade_functions.erl | 14 +- .../rabbit/src/rabbit_variable_queue.erl | 188 +- .../rabbit/src/rabbit_version.erl | 2 +- .../deps => deps}/rabbit/src/rabbit_vhost.erl | 9 +- .../deps => deps}/rabbit/src/rabbit_vm.erl | 59 +- .../rabbit/src/supervised_lifecycle.erl | 2 +- .../deps => deps}/rabbit/src/tcp_listener.erl | 2 +- .../rabbit/src/tcp_listener_sup.erl | 2 +- .../deps => deps}/rabbit/src/truncate.erl | 2 +- .../rabbit}/src/vm_memory_monitor.erl | 233 +- .../rabbit}/src/worker_pool.erl | 2 +- .../rabbit}/src/worker_pool_sup.erl | 2 +- .../rabbit}/src/worker_pool_worker.erl | 49 +- .../rabbit_common/CODE_OF_CONDUCT.md | 0 .../rabbit_common}/CONTRIBUTING.md | 0 .../deps => deps}/rabbit_common/LICENSE | 0 .../rabbit_common/LICENSE-MIT-Erlware-Commons | 0 .../rabbit_common/LICENSE-MPL-RabbitMQ | 0 .../rabbit_common/Makefile | 36 + .../deps => deps}/rabbit_common/codegen.py | 0 .../rabbit_common}/erlang.mk | 1129 ++- .../include/old_builtin_types.hrl | 0 .../rabbit_common/include/rabbit.hrl | 16 +- .../rabbit_common/include/rabbit_misc.hrl | 0 .../include/rabbit_msg_store.hrl | 2 +- deps/rabbit_common/mk/rabbitmq-build.mk | 70 + .../rabbit_common/mk}/rabbitmq-components.mk | 62 +- .../rabbit_common/mk/rabbitmq-dist.mk | 0 .../rabbit_common/mk/rabbitmq-plugin.mk | 8 - .../rabbit_common/mk/rabbitmq-run.mk | 15 +- .../rabbit_common/mk/rabbitmq-tools.mk | 0 .../rabbit_common/src/app_utils.erl | 7 +- .../rabbit_common/src/code_version.erl | 13 +- .../rabbit_common/src/credit_flow.erl | 2 +- .../rabbit_common/src/ec_semver.erl | 6 +- .../rabbit_common/src/ec_semver_parser.erl | 4 +- .../rabbit_common/src/gen_server2.erl | 94 +- .../rabbit_common/src/mirrored_supervisor.erl | 0 .../rabbit_common/src/mochijson2.erl | 0 .../rabbit_common/src/mochinum.erl | 0 .../deps => deps}/rabbit_common/src/pmon.erl | 0 .../rabbit_common/src/priority_queue.erl | 2 +- .../rabbit_common}/src/rabbit_amqqueue.erl | 114 +- .../src/rabbit_auth_backend_dummy.erl | 2 +- .../src/rabbit_auth_backend_internal.erl | 31 +- .../src/rabbit_auth_mechanism.erl | 2 +- .../src/rabbit_authn_backend.erl | 2 +- .../src/rabbit_authz_backend.erl | 2 +- .../src/rabbit_backing_queue.erl | 5 +- .../rabbit_common}/src/rabbit_basic.erl | 32 +- .../src/rabbit_binary_generator.erl | 2 +- .../src/rabbit_binary_parser.erl | 9 +- .../rabbit_common}/src/rabbit_channel.erl | 68 +- .../src/rabbit_channel_interceptor.erl | 2 +- .../src/rabbit_command_assembler.erl | 2 +- deps/rabbit_common/src/rabbit_common.app.src | 14 + .../rabbit_common/src/rabbit_control_misc.erl | 2 +- .../src/rabbit_data_coercion.erl | 12 +- .../src/rabbit_error_logger_handler.erl | 2 +- .../rabbit_common/src/rabbit_event.erl | 2 +- .../src/rabbit_exchange_decorator.erl | 2 +- .../src/rabbit_exchange_type.erl | 2 +- .../src/rabbit_health_check.erl | 2 +- .../rabbit_common/src/rabbit_heartbeat.erl | 2 +- .../rabbit_common/src/rabbit_misc.erl | 83 +- .../src/rabbit_msg_store_index.erl | 2 +- .../rabbit_common/src/rabbit_net.erl | 55 +- .../rabbit_common}/src/rabbit_networking.erl | 138 +- .../rabbit_common}/src/rabbit_nodes.erl | 33 +- .../src/rabbit_password_hashing.erl | 2 +- .../src/rabbit_policy_validator.erl | 2 +- .../src/rabbit_queue_collector.erl | 5 +- .../src/rabbit_queue_decorator.erl | 2 +- .../src/rabbit_queue_master_locator.erl | 2 +- .../rabbit_common}/src/rabbit_reader.erl | 96 +- .../src/rabbit_runtime_parameter.erl | 2 +- .../rabbit_common/src/rabbit_types.erl | 6 +- .../rabbit_common/src/rabbit_writer.erl | 39 +- .../rabbit_common/src/rand_compat.erl | 0 .../rabbit_common/src/ssl_compat.erl | 6 +- .../rabbit_common/src/supervisor2.erl | 3 +- .../rabbit_common/src/time_compat.erl | 0 .../rabbitmq_amqp1_0/CODE_OF_CONDUCT.md | 0 .../rabbitmq_amqp1_0}/CONTRIBUTING.md | 0 .../deps => deps}/rabbitmq_amqp1_0/Makefile | 19 +- .../deps => deps}/rabbitmq_amqp1_0/README.md | 0 .../deps => deps}/rabbitmq_amqp1_0/codegen.py | 0 .../rabbitmq_amqp1_0}/erlang.mk | 1129 ++- .../include/rabbit_amqp1_0.hrl | 0 .../rabbitmq_amqp1_0}/rabbitmq-components.mk | 62 +- .../rabbitmq_amqp1_0/spec}/messaging.xml | 0 .../rabbitmq_amqp1_0/spec}/security.xml | 0 .../rabbitmq_amqp1_0/spec}/transactions.xml | 0 .../rabbitmq_amqp1_0/spec}/transport.xml | 0 .../rabbitmq_amqp1_0/spec}/types.xml | 0 .../src/rabbit_amqp1_0_binary_generator.erl | 2 +- .../src/rabbit_amqp1_0_binary_parser.erl | 2 +- .../src/rabbit_amqp1_0_channel.erl | 2 +- .../src/rabbit_amqp1_0_framing.erl | 20 +- .../src/rabbit_amqp1_0_incoming_link.erl | 2 +- .../src/rabbit_amqp1_0_link_util.erl | 2 +- .../src/rabbit_amqp1_0_message.erl | 16 +- .../src/rabbit_amqp1_0_outgoing_link.erl | 2 +- .../src/rabbit_amqp1_0_reader.erl | 2 +- .../src/rabbit_amqp1_0_session.erl | 2 +- .../src/rabbit_amqp1_0_session_process.erl | 2 +- .../src/rabbit_amqp1_0_session_sup.erl | 2 +- .../src/rabbit_amqp1_0_session_sup_sup.erl | 2 +- .../src/rabbit_amqp1_0_util.erl | 2 +- .../src/rabbit_amqp1_0_writer.erl | 2 +- .../src/rabbitmq_amqp1_0.app.src | 9 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 deps/rabbitmq_auth_backend_ldap/Makefile | 16 + .../README-authorisation.md | 0 .../README-tests.md | 0 .../rabbitmq_auth_backend_ldap/README.md | 0 .../rabbitmq_auth_backend_ldap/Vagrantfile | 0 deps/rabbitmq_auth_backend_ldap/erlang.mk | 6738 ++++++++++++++++ .../example/global.ldif | 0 .../example/memberof_init.ldif | 0 .../example/refint_1.ldif | 0 .../example/refint_2.ldif | 0 .../example/seed.sh | 0 .../example/setup.sh | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_auth_backend_ldap.erl | 99 +- .../src/rabbit_auth_backend_ldap_app.erl | 8 +- .../src/rabbit_auth_backend_ldap_util.erl | 2 +- .../src/rabbitmq_auth_backend_ldap.app.src | 25 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_auth_mechanism_ssl/Makefile | 9 - deps/rabbitmq_auth_mechanism_ssl/README.md | 62 + deps/rabbitmq_auth_mechanism_ssl/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq-components.mk | 284 + .../src/rabbit_auth_mechanism_ssl.erl | 2 +- .../src/rabbit_auth_mechanism_ssl_app.erl | 2 +- .../src/rabbitmq_auth_mechanism_ssl.app.src | 9 + .../rabbitmq_codegen/CODE_OF_CONDUCT.md | 0 .../rabbitmq_codegen}/CONTRIBUTING.md | 0 .../deps => deps}/rabbitmq_codegen/LICENSE | 0 .../rabbitmq_codegen/LICENSE-MPL-RabbitMQ | 0 .../deps => deps}/rabbitmq_codegen/Makefile | 0 .../rabbitmq_codegen/README.extensions.md | 0 .../rabbitmq_codegen/amqp-rabbitmq-0.8.json | 0 .../rabbitmq_codegen/amqp-rabbitmq-0.9.1.json | 0 .../rabbitmq_codegen/amqp_codegen.py | 29 +- .../rabbitmq_codegen/credit_extension.json | 0 .../rabbitmq_codegen/demo_extension.json | 0 .../rabbitmq_codegen/license_info | 0 .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_consistent_hash_exchange/LICENSE | 0 .../LICENSE-MPL-RabbitMQ | 0 .../Makefile | 4 +- .../README.md | 0 .../erlang.mk | 6738 ++++++++++++++++ .../rabbitmq-components.mk | 284 + .../rabbit_exchange_type_consistent_hash.erl | 16 +- .../rabbitmq_consistent_hash_exchange.app.src | 7 + .../CODE_OF_CONDUCT.md | 0 .../rabbitmq_event_exchange}/CONTRIBUTING.md | 0 .../rabbitmq_event_exchange/LICENSE | 0 .../LICENSE-MPL-RabbitMQ | 0 .../rabbitmq_event_exchange/Makefile | 4 +- .../rabbitmq_event_exchange/README.md | 103 +- deps/rabbitmq_event_exchange/erlang.mk | 6738 ++++++++++++++++ .../examples/java/QueueEvents.java | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_exchange_type_event.erl | 2 +- .../src/rabbitmq_event_exchange.app.src | 7 + .../rabbitmq_federation/CODE_OF_CONDUCT.md | 0 .../rabbitmq_federation}/CONTRIBUTING.md | 0 deps/rabbitmq_federation/Makefile | 15 + .../rabbitmq_federation/README-hacking | 0 .../rabbitmq_federation/README.md | 0 deps/rabbitmq_federation/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq_federation/etc/rabbit-test.sh | 0 .../etc/setup-rabbit-test.sh | 0 .../include/rabbit_federation.hrl | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_federation_app.erl | 2 +- .../src/rabbit_federation_db.erl | 2 +- .../src/rabbit_federation_event.erl | 2 +- .../src/rabbit_federation_exchange.erl | 2 +- .../src/rabbit_federation_exchange_link.erl | 88 +- ...abbit_federation_exchange_link_sup_sup.erl | 4 +- .../src/rabbit_federation_link_sup.erl | 9 +- .../src/rabbit_federation_link_util.erl | 6 +- .../src/rabbit_federation_parameters.erl | 2 +- .../src/rabbit_federation_queue.erl | 2 +- .../src/rabbit_federation_queue_link.erl | 3 +- .../rabbit_federation_queue_link_sup_sup.erl | 4 +- .../src/rabbit_federation_status.erl | 63 +- .../src/rabbit_federation_sup.erl | 8 +- .../src/rabbit_federation_upstream.erl | 2 +- .../rabbit_federation_upstream_exchange.erl | 2 +- .../src/rabbit_federation_util.erl | 2 +- .../src/rabbitmq_federation.app.src | 8 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_federation_management/LICENSE | 0 .../LICENSE-APACHE2-ExplorerCanvas | 0 .../LICENSE-BSD-base64js | 0 .../LICENSE-MIT-EJS10 | 0 .../LICENSE-MIT-Flot | 0 .../LICENSE-MIT-Sammy060 | 0 .../LICENSE-MIT-jQuery164 | 0 .../LICENSE-MPL-RabbitMQ | 0 .../rabbitmq_federation_management/Makefile | 5 +- .../rabbitmq_federation_management/README.md | 2 +- deps/rabbitmq_federation_management/erlang.mk | 6738 ++++++++++++++++ .../priv/www/js/federation.js | 7 +- .../priv/www/js/tmpl/federation-upstream.ejs | 0 .../priv/www/js/tmpl/federation-upstreams.ejs | 0 .../priv/www/js/tmpl/federation.ejs | 11 - .../rabbitmq-components.mk | 284 + .../src/rabbit_federation_mgmt.erl | 97 + .../rabbitmq_federation_management.app.src | 8 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_jms_topic_exchange/LICENSE | 0 .../rabbitmq_jms_topic_exchange/LICENSES.txt | 0 .../rabbitmq_jms_topic_exchange/Makefile | 4 +- .../rabbitmq_jms_topic_exchange/README.md | 2 +- deps/rabbitmq_jms_topic_exchange/erlang.mk | 6738 ++++++++++++++++ .../include/rabbit_jms_topic_exchange.hrl | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_jms_topic_exchange.erl | 0 .../src/rabbitmq_jms_topic_exchange.app.src | 8 + .../src/sjx_evaluator.erl | 0 .../rabbitmq_management/CODE_OF_CONDUCT.md | 0 .../rabbitmq_management}/CONTRIBUTING.md | 0 .../deps => deps}/rabbitmq_management/LICENSE | 3 +- .../LICENSE-APACHE2-ExplorerCanvas | 0 .../rabbitmq_management/LICENSE-BSD-base64js | 0 .../rabbitmq_management/LICENSE-MIT-EJS10 | 0 .../rabbitmq_management/LICENSE-MIT-Flot | 0 .../rabbitmq_management/LICENSE-MIT-Sammy060 | 0 .../rabbitmq_management/LICENSE-MIT-jQuery164 | 0 .../rabbitmq_management/LICENSE-MPL-RabbitMQ | 0 deps/rabbitmq_management/Makefile | 31 + deps/rabbitmq_management/README.md | 13 + .../rabbitmq_management/bin/rabbitmqadmin | 108 +- deps/rabbitmq_management/erlang.mk | 6738 ++++++++++++++++ .../include/rabbit_mgmt.hrl | 5 + .../include/rabbit_mgmt_event_collector.hrl | 32 + .../include/rabbit_mgmt_metrics.hrl | 211 + .../include/rabbit_mgmt_test.hrl | 11 + .../rabbitmq_management/license_info | 0 .../priv/www/api/index.html | 77 +- .../priv/www/cli/index.html | 5 +- .../rabbitmq_management/priv/www/css/evil.css | 0 .../rabbitmq_management/priv/www/css/main.css | 0 .../priv/www/doc/stats.html | 0 .../rabbitmq_management/priv/www/favicon.ico | Bin .../priv/www/img/bg-binary.png | Bin .../priv/www/img/bg-green-dark.png | Bin .../priv/www/img/bg-red-dark.png | Bin .../priv/www/img/bg-red.png | Bin .../priv/www/img/bg-yellow-dark.png | Bin .../priv/www/img/collapse.png | Bin .../priv/www/img/expand.png | Bin .../priv/www/img/rabbitmqlogo.png | Bin .../rabbitmq_management/priv/www/index.html | 0 .../rabbitmq_management/priv/www/js/base64.js | 0 .../rabbitmq_management/priv/www/js/charts.js | 12 +- .../priv/www/js/dispatcher.js | 14 +- .../rabbitmq_management/priv/www/js/ejs.js | 0 .../priv/www/js/ejs.min.js | 0 .../priv/www/js/excanvas.js | 0 .../priv/www/js/excanvas.min.js | 0 .../priv/www/js/formatters.js | 55 +- .../rabbitmq_management/priv/www/js/global.js | 8 +- .../rabbitmq_management/priv/www/js/help.js | 28 +- .../priv/www/js/jquery-1.6.4.js | 0 .../priv/www/js/jquery-1.6.4.min.js | 0 .../priv/www/js/jquery.flot.js | 0 .../priv/www/js/jquery.flot.min.js | 0 .../priv/www/js/jquery.flot.time.js | 0 .../priv/www/js/jquery.flot.time.min.js | 0 .../rabbitmq_management/priv/www/js/json2.js | 0 .../rabbitmq_management/priv/www/js/main.js | 119 +- .../rabbitmq_management/priv/www/js/prefs.js | 39 +- .../rabbitmq_management/priv/www/js/sammy.js | 0 .../priv/www/js/sammy.min.js | 0 .../priv/www/js/tmpl/404.ejs | 0 .../priv/www/js/tmpl/add-binding.ejs | 0 .../priv/www/js/tmpl/binary.ejs | 0 .../priv/www/js/tmpl/bindings.ejs | 0 .../priv/www/js/tmpl/channel.ejs | 0 .../priv/www/js/tmpl/channels-list.ejs | 0 .../priv/www/js/tmpl/channels.ejs | 0 .../priv/www/js/tmpl/cluster-name.ejs | 0 .../priv/www/js/tmpl/columns-options.ejs | 0 .../priv/www/js/tmpl/connection.ejs | 0 .../priv/www/js/tmpl/connections.ejs | 0 .../priv/www/js/tmpl/consumers.ejs | 0 .../priv/www/js/tmpl/error-popup.ejs | 0 .../priv/www/js/tmpl/exchange.ejs | 0 .../priv/www/js/tmpl/exchanges.ejs | 2 +- .../priv/www/js/tmpl/import-succeeded.ejs | 0 .../priv/www/js/tmpl/layout.ejs | 0 .../priv/www/js/tmpl/login.ejs | 0 .../priv/www/js/tmpl/memory-bar.ejs | 0 .../priv/www/js/tmpl/memory-table.ejs | 0 .../priv/www/js/tmpl/memory.ejs | 0 .../priv/www/js/tmpl/messages.ejs | 0 .../www/js/tmpl/msg-detail-deliveries.ejs | 0 .../priv/www/js/tmpl/msg-detail-publishes.ejs | 0 .../priv/www/js/tmpl/node.ejs | 13 - .../priv/www/js/tmpl/overview.ejs | 76 +- .../priv/www/js/tmpl/partition.ejs | 0 .../priv/www/js/tmpl/paths.ejs | 0 .../priv/www/js/tmpl/permissions.ejs | 0 .../priv/www/js/tmpl/policies.ejs | 6 +- .../priv/www/js/tmpl/policy.ejs | 0 .../priv/www/js/tmpl/publish.ejs | 0 .../priv/www/js/tmpl/queue.ejs | 28 +- .../priv/www/js/tmpl/queues.ejs | 7 +- .../priv/www/js/tmpl/rate-options.ejs | 0 .../priv/www/js/tmpl/registry.ejs | 0 .../priv/www/js/tmpl/status.ejs | 0 .../priv/www/js/tmpl/user.ejs | 1 - .../priv/www/js/tmpl/users.ejs | 3 +- .../priv/www/js/tmpl/vhost.ejs | 0 .../priv/www/js/tmpl/vhosts.ejs | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_mgmt_app.erl | 114 + .../rabbit_mgmt_channel_stats_collector.erl | 125 + .../src/rabbit_mgmt_cors.erl | 88 + .../src/rabbit_mgmt_db.erl | 702 ++ .../src/rabbit_mgmt_dispatcher.erl | 101 + .../src/rabbit_mgmt_event_collector.erl | 165 + .../src/rabbit_mgmt_event_collector_utils.erl | 551 ++ .../src/rabbit_mgmt_extension.erl | 19 +- .../src/rabbit_mgmt_format.erl | 160 +- .../src/rabbit_mgmt_load_definitions.erl | 2 +- .../src/rabbit_mgmt_queue_stats_collector.erl | 120 + .../src/rabbit_mgmt_reset_handler.erl | 6 +- .../src/rabbit_mgmt_stats.erl | 978 +++ .../src/rabbit_mgmt_stats_gc.erl | 219 + .../src/rabbit_mgmt_stats_tables.erl | 271 + .../src/rabbit_mgmt_sup.erl | 50 + .../src/rabbit_mgmt_sup_sup.erl | 71 + .../src/rabbit_mgmt_util.erl | 426 +- .../src/rabbit_mgmt_wm_aliveness_test.erl | 26 +- .../src/rabbit_mgmt_wm_binding.erl | 59 +- .../src/rabbit_mgmt_wm_bindings.erl | 69 +- .../src/rabbit_mgmt_wm_channel.erl | 30 +- .../src/rabbit_mgmt_wm_channels.erl | 26 +- .../src/rabbit_mgmt_wm_channels_vhost.erl | 24 +- .../src/rabbit_mgmt_wm_cluster_name.erl | 40 +- .../src/rabbit_mgmt_wm_connection.erl | 33 +- .../rabbit_mgmt_wm_connection_channels.erl | 26 +- .../src/rabbit_mgmt_wm_connections.erl | 26 +- .../src/rabbit_mgmt_wm_connections_vhost.erl | 24 +- .../src/rabbit_mgmt_wm_consumers.erl | 44 +- .../src/rabbit_mgmt_wm_definitions.erl | 219 +- .../src/rabbit_mgmt_wm_exchange.erl | 34 +- .../src/rabbit_mgmt_wm_exchange_publish.erl | 47 +- .../src/rabbit_mgmt_wm_exchanges.erl | 43 +- .../src/rabbit_mgmt_wm_extensions.erl | 25 +- .../src/rabbit_mgmt_wm_healthchecks.erl | 56 +- .../src/rabbit_mgmt_wm_node.erl | 30 +- .../src/rabbit_mgmt_wm_node_memory.erl | 29 +- .../src/rabbit_mgmt_wm_node_memory_ets.erl | 27 +- .../src/rabbit_mgmt_wm_nodes.erl | 26 +- .../src/rabbit_mgmt_wm_overview.erl | 42 +- .../src/rabbit_mgmt_wm_parameter.erl | 45 +- .../src/rabbit_mgmt_wm_parameters.erl | 26 +- .../src/rabbit_mgmt_wm_permission.erl | 44 +- .../src/rabbit_mgmt_wm_permissions.erl | 26 +- .../src/rabbit_mgmt_wm_permissions_user.erl | 26 +- .../src/rabbit_mgmt_wm_permissions_vhost.erl | 26 +- .../src/rabbit_mgmt_wm_policies.erl | 26 +- .../src/rabbit_mgmt_wm_policy.erl | 43 +- .../src/rabbit_mgmt_wm_queue.erl | 55 +- .../src/rabbit_mgmt_wm_queue_actions.erl | 43 +- .../src/rabbit_mgmt_wm_queue_get.erl | 50 +- .../src/rabbit_mgmt_wm_queue_purge.erl | 26 +- .../src/rabbit_mgmt_wm_queues.erl | 64 +- .../src/rabbit_mgmt_wm_user.erl | 147 + .../src/rabbit_mgmt_wm_users.erl | 26 +- .../src/rabbit_mgmt_wm_vhost.erl | 38 +- .../src/rabbit_mgmt_wm_vhosts.erl | 43 +- .../src/rabbit_mgmt_wm_whoami.erl | 27 +- .../src/rabbitmq_management.app.src | 22 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_management_agent/LICENSE | 0 .../LICENSE-MPL-RabbitMQ | 0 deps/rabbitmq_management_agent/Makefile | 14 + deps/rabbitmq_management_agent/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq-components.mk | 284 + .../src/rabbit_mgmt_agent_app.erl | 4 +- .../src/rabbit_mgmt_agent_sup.erl | 18 +- .../src/rabbit_mgmt_db_handler.erl | 31 +- .../src/rabbit_mgmt_external_stats.erl | 108 +- .../src/rabbitmq_management_agent.app.src | 8 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_management_visualiser/LICENSE | 0 .../LICENSE-BSD-glMatrix | 0 .../LICENSE-MPL-RabbitMQ | 0 .../rabbitmq_management_visualiser/Makefile | 5 +- .../rabbitmq_management_visualiser/README | 31 +- deps/rabbitmq_management_visualiser/erlang.mk | 6738 ++++++++++++++++ .../license_info | 0 .../priv/www/js/visualiser.js | 3 + .../priv/www/visualiser/index.html | 0 .../priv/www/visualiser/js/glMatrix-min.js | 0 .../priv/www/visualiser/js/glMatrix.js | 0 .../priv/www/visualiser/js/main.js | 0 .../priv/www/visualiser/js/model.js | 0 .../priv/www/visualiser/js/octtree.js | 0 .../priv/www/visualiser/js/physics.js | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_mgmt_wm_all.erl | 32 +- .../src/rabbit_visualiser_mgmt.erl | 6 +- .../rabbitmq_management_visualiser.app.src | 6 + .../rabbitmq_mqtt/CODE_OF_CONDUCT.md | 0 .../rabbitmq_mqtt}/CONTRIBUTING.md | 0 deps/rabbitmq_mqtt/Makefile | 22 + .../deps => deps}/rabbitmq_mqtt/README.md | 0 deps/rabbitmq_mqtt/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq_mqtt/include/rabbit_mqtt.hrl | 33 - .../include/rabbit_mqtt_frame.hrl | 0 .../rabbit_mqtt_retained_msg_store.hrl | 0 deps/rabbitmq_mqtt/rabbitmq-components.mk | 284 + .../rabbitmq_mqtt/src/rabbit_mqtt.erl | 2 +- .../src/rabbit_mqtt_collector.erl | 15 +- .../src/rabbit_mqtt_connection_sup.erl | 2 +- .../rabbitmq_mqtt/src/rabbit_mqtt_frame.erl | 2 +- .../src/rabbit_mqtt_processor.erl | 204 +- .../rabbitmq_mqtt/src/rabbit_mqtt_reader.erl | 92 +- .../src/rabbit_mqtt_retained_msg_store.erl | 0 .../rabbit_mqtt_retained_msg_store_dets.erl | 0 .../rabbit_mqtt_retained_msg_store_ets.erl | 0 .../src/rabbit_mqtt_retainer.erl | 0 .../src/rabbit_mqtt_retainer_sup.erl | 15 +- .../rabbitmq_mqtt/src/rabbit_mqtt_sup.erl | 2 +- .../rabbitmq_mqtt/src/rabbit_mqtt_util.erl | 13 +- .../src/rabbit_mqtt_vhost_event_handler.erl | 0 deps/rabbitmq_mqtt/src/rabbitmq_mqtt.app.src | 25 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../LICENSE.md | 0 .../rabbitmq_recent_history_exchange/Makefile | 4 +- .../README.md | 0 .../erlang.mk | 6738 ++++++++++++++++ .../etc/rabbit-hare.config | 0 .../etc/rabbit-test.config | 0 .../include/rabbit_recent_history.hrl | 0 .../rabbitmq-components.mk | 284 + .../rabbit_exchange_type_recent_history.erl | 2 +- .../rabbitmq_recent_history_exchange.app.src | 6 + .../rabbitmq_sharding/CODE_OF_CONDUCT.md | 0 .../rabbitmq_sharding}/CONTRIBUTING.md | 0 .../deps => deps}/rabbitmq_sharding/LICENSE | 0 .../rabbitmq_sharding/LICENSE-MPL-RabbitMQ | 0 .../rabbitmq_sharding/LICENSE-MPL2 | 0 .../deps => deps}/rabbitmq_sharding/Makefile | 4 +- .../rabbitmq_sharding/README.extra.md | 0 .../deps => deps}/rabbitmq_sharding/README.md | 0 .../rabbitmq_sharding/docs/sharded_queues.png | Bin deps/rabbitmq_sharding/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq_sharding/etc/rabbit-hare.config | 0 .../rabbitmq_sharding/etc/rabbit-test.config | 0 .../rabbitmq_sharding/etc/rkey.sh | 0 deps/rabbitmq_sharding/rabbitmq-components.mk | 284 + .../rabbit_sharding_exchange_decorator.erl | 2 +- ...it_sharding_exchange_type_modulus_hash.erl | 2 +- .../src/rabbit_sharding_interceptor.erl | 2 +- .../src/rabbit_sharding_policy_validator.erl | 2 +- .../src/rabbit_sharding_shard.erl | 2 +- .../src/rabbit_sharding_util.erl | 2 +- .../src/rabbitmq_sharding.app.src | 6 + .../rabbitmq_shovel/CODE_OF_CONDUCT.md | 0 .../rabbitmq_shovel}/CONTRIBUTING.md | 0 deps/rabbitmq_shovel/Makefile | 15 + .../deps => deps}/rabbitmq_shovel/README.md | 2 +- deps/rabbitmq_shovel/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq_shovel/include/rabbit_shovel.hrl | 0 deps/rabbitmq_shovel/rabbitmq-components.mk | 284 + .../rabbitmq_shovel/src/rabbit_shovel.erl | 2 +- .../src/rabbit_shovel_config.erl | 2 +- .../src/rabbit_shovel_dyn_worker_sup.erl | 2 +- .../src/rabbit_shovel_dyn_worker_sup_sup.erl | 2 +- .../src/rabbit_shovel_parameters.erl | 2 +- .../src/rabbit_shovel_status.erl | 2 +- .../rabbitmq_shovel/src/rabbit_shovel_sup.erl | 2 +- .../src/rabbit_shovel_util.erl | 2 +- .../src/rabbit_shovel_worker.erl | 2 +- .../src/rabbit_shovel_worker_sup.erl | 2 +- .../src/rabbitmq_shovel.app.src | 13 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_shovel_management/Makefile | 6 +- .../rabbitmq_shovel_management/README.md | 2 +- deps/rabbitmq_shovel_management/erlang.mk | 6738 ++++++++++++++++ .../priv/www/js/shovel.js | 0 .../priv/www/js/tmpl/dynamic-shovel.ejs | 0 .../priv/www/js/tmpl/dynamic-shovels.ejs | 0 .../priv/www/js/tmpl/shovels.ejs | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_shovel_mgmt.erl | 19 +- .../src/rabbitmq_shovel_management.app.src | 6 + .../rabbitmq_stomp/CODE_OF_CONDUCT.md | 0 .../rabbitmq_stomp}/CONTRIBUTING.md | 0 deps/rabbitmq_stomp/Makefile | 15 + .../deps => deps}/rabbitmq_stomp/NOTES | 0 .../deps => deps}/rabbitmq_stomp/README.md | 0 deps/rabbitmq_stomp/erlang.mk | 6738 ++++++++++++++++ .../examples/perl/rabbitmq_stomp_recv.pl | 0 .../perl/rabbitmq_stomp_rpc_client.pl | 0 .../perl/rabbitmq_stomp_rpc_service.pl | 0 .../examples/perl/rabbitmq_stomp_send.pl | 0 .../examples/perl/rabbitmq_stomp_send_many.pl | 0 .../examples/perl/rabbitmq_stomp_slow_recv.pl | 0 .../examples/ruby/cb-receiver.rb | 0 .../rabbitmq_stomp/examples/ruby/cb-sender.rb | 0 .../examples/ruby/cb-slow-receiver.rb | 0 .../examples/ruby/persistent-receiver.rb | 0 .../examples/ruby/persistent-sender.rb | 0 .../examples/ruby/topic-broadcast-receiver.rb | 0 .../ruby/topic-broadcast-with-unsubscribe.rb | 0 .../examples/ruby/topic-sender.rb | 0 .../rabbitmq_stomp/include/rabbit_stomp.hrl | 23 - .../include/rabbit_stomp_frame.hrl | 0 .../include/rabbit_stomp_headers.hrl | 0 deps/rabbitmq_stomp/rabbitmq-components.mk | 284 + .../rabbitmq_stomp/src/rabbit_stomp.erl | 12 +- .../src/rabbit_stomp_client_sup.erl | 2 +- .../rabbitmq_stomp/src/rabbit_stomp_frame.erl | 2 +- .../src/rabbit_stomp_processor.erl | 86 +- .../src/rabbit_stomp_reader.erl | 106 +- .../rabbitmq_stomp/src/rabbit_stomp_sup.erl | 2 +- .../rabbitmq_stomp/src/rabbit_stomp_util.erl | 7 +- .../rabbitmq_stomp/src/rabbitmq_stomp.app.src | 23 + .../rabbitmq_top/CODE_OF_CONDUCT.md | 0 .../rabbitmq_top}/CONTRIBUTING.md | 0 .../deps => deps}/rabbitmq_top/Makefile | 3 - .../deps => deps}/rabbitmq_top/README.md | 0 deps/rabbitmq_top/erlang.mk | 6738 ++++++++++++++++ .../priv/www/js/tmpl/ets_tables.ejs | 0 .../rabbitmq_top/priv/www/js/tmpl/process.ejs | 4 - .../priv/www/js/tmpl/processes.ejs | 2 - .../rabbitmq_top/priv/www/js/top.js | 8 +- deps/rabbitmq_top/rabbitmq-components.mk | 284 + .../rabbitmq_top/src/rabbit_top_app.erl | 2 +- .../rabbitmq_top/src/rabbit_top_extension.erl | 6 +- .../rabbitmq_top/src/rabbit_top_sup.erl | 0 .../rabbitmq_top/src/rabbit_top_util.erl | 27 +- .../src/rabbit_top_wm_ets_tables.erl | 39 +- .../src/rabbit_top_wm_process.erl | 12 +- .../src/rabbit_top_wm_processes.erl | 39 +- .../rabbitmq_top/src/rabbit_top_worker.erl | 15 +- deps/rabbitmq_top/src/rabbitmq_top.app.src | 7 + .../rabbitmq_tracing/CODE_OF_CONDUCT.md | 0 .../rabbitmq_tracing}/CONTRIBUTING.md | 0 deps/rabbitmq_tracing/Makefile | 15 + .../deps => deps}/rabbitmq_tracing/README.md | 0 deps/rabbitmq_tracing/erlang.mk | 6738 ++++++++++++++++ .../priv/www/js/tmpl/traces.ejs | 0 .../rabbitmq_tracing/priv/www/js/tracing.js | 0 deps/rabbitmq_tracing/rabbitmq-components.mk | 284 + .../src/rabbit_tracing_app.erl | 2 +- .../src/rabbit_tracing_consumer.erl | 2 +- .../src/rabbit_tracing_consumer_sup.erl | 2 +- .../src/rabbit_tracing_files.erl | 2 +- .../src/rabbit_tracing_mgmt.erl | 12 +- .../src/rabbit_tracing_sup.erl | 2 +- .../src/rabbit_tracing_traces.erl | 2 +- .../src/rabbit_tracing_util.erl | 0 .../src/rabbit_tracing_wm_file.erl | 16 +- .../src/rabbit_tracing_wm_files.erl | 13 +- .../src/rabbit_tracing_wm_trace.erl | 34 +- .../src/rabbit_tracing_wm_traces.erl | 13 +- .../src/rabbitmq_tracing.app.src | 10 + .../rabbitmq_trust_store/CODE_OF_CONDUCT.md | 0 .../rabbitmq_trust_store}/CONTRIBUTING.md | 0 deps/rabbitmq_trust_store/Makefile | 17 + .../rabbitmq_trust_store/README.md | 68 +- deps/rabbitmq_trust_store/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq-components.mk | 284 + .../src/rabbit_trust_store.erl | 282 + .../src/rabbit_trust_store_app.erl | 75 +- .../src/rabbit_trust_store_sup.erl | 13 +- .../src/rabbitmq_trust_store.app.src | 16 + .../rabbitmq_web_dispatch/CODE_OF_CONDUCT.md | 0 .../rabbitmq_web_dispatch}/CONTRIBUTING.md | 0 .../rabbitmq_web_dispatch/LICENSE | 0 deps/rabbitmq_web_dispatch/Makefile | 15 + deps/rabbitmq_web_dispatch/README.md | 25 + deps/rabbitmq_web_dispatch/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq-components.mk | 284 + .../src/rabbit_web_dispatch.erl | 51 +- .../src/rabbit_web_dispatch_app.erl | 2 +- .../src/rabbit_web_dispatch_registry.erl | 78 +- .../src/rabbit_web_dispatch_sup.erl | 76 +- .../src/rabbit_web_dispatch_util.erl | 3 +- .../src/rabbit_webmachine.erl | 68 + .../src/rabbit_webmachine_error_handler.erl | 63 + .../src/rabbitmq_web_dispatch.app.src | 8 + .../rabbitmq_web_stomp}/CODE_OF_CONDUCT.md | 0 .../rabbitmq_web_stomp}/CONTRIBUTING.md | 0 .../rabbitmq_web_stomp}/LICENSE | 0 .../rabbitmq_web_stomp}/LICENSE-MPL-RabbitMQ | 0 .../deps => deps}/rabbitmq_web_stomp/Makefile | 19 +- deps/rabbitmq_web_stomp/README.md | 45 + deps/rabbitmq_web_stomp/erlang.mk | 6738 ++++++++++++++++ .../rabbitmq_web_stomp/rabbitmq-components.mk | 284 + .../rabbitmq_web_stomp/src/rabbit_ws_app.erl | 2 +- .../src/rabbit_ws_client.erl | 15 +- .../src/rabbit_ws_client_sup.erl | 2 +- .../src/rabbit_ws_handler.erl | 0 .../src/rabbit_ws_sockjs.erl | 101 + .../rabbitmq_web_stomp/src/rabbit_ws_sup.erl | 2 +- .../src/rabbitmq_web_stomp.app.src | 18 + .../CODE_OF_CONDUCT.md | 0 .../CONTRIBUTING.md | 0 .../rabbitmq_web_stomp_examples/LICENSE | 0 .../LICENSE-APL2-Stomp-Websocket | 0 .../LICENSE-MPL-RabbitMQ | 0 .../rabbitmq_web_stomp_examples/Makefile | 9 - .../rabbitmq_web_stomp_examples/README.md | 0 deps/rabbitmq_web_stomp_examples/erlang.mk | 6738 ++++++++++++++++ .../priv/bunny.html | 0 .../priv/bunny.png | Bin .../priv/echo.html | 0 .../priv/index.html | 0 .../priv/main.css | 0 .../priv/pencil.cur | Bin .../rabbitmq_web_stomp_examples/priv/stomp.js | 0 .../priv/temp-queue.html | 0 .../rabbitmq-components.mk | 284 + .../src/rabbit_web_stomp_examples_app.erl | 2 +- .../src/rabbitmq_web_stomp_examples.app.src | 8 + deps/ranch/AUTHORS | 33 + .../deps => deps}/ranch/CHANGELOG.asciidoc | 22 - {rabbitmq-server/deps => deps}/ranch/LICENSE | 2 +- {rabbitmq-server/deps => deps}/ranch/Makefile | 26 +- .../deps => deps}/ranch/README.asciidoc | 20 +- deps/ranch/appveyor.yml | 7 + .../deps/cowlib => deps/ranch}/circle.yml | 8 +- deps/ranch/doc/src/guide/book.asciidoc | 20 + deps/ranch/doc/src/guide/embedded.asciidoc | 48 + deps/ranch/doc/src/guide/internals.asciidoc | 94 + .../ranch/doc/src/guide/introduction.asciidoc | 25 + deps/ranch/doc/src/guide/listeners.asciidoc | 251 + deps/ranch/doc/src/guide/parsers.asciidoc | 92 + deps/ranch/doc/src/guide/protocols.asciidoc | 125 + deps/ranch/doc/src/guide/ssl_auth.asciidoc | 120 + deps/ranch/doc/src/guide/transports.asciidoc | 169 + deps/ranch/doc/src/manual/ranch.asciidoc | 178 + deps/ranch/doc/src/manual/ranch_app.asciidoc | 27 + .../doc/src/manual/ranch_protocol.asciidoc | 44 + deps/ranch/doc/src/manual/ranch_ssl.asciidoc | 142 + deps/ranch/doc/src/manual/ranch_tcp.asciidoc | 123 + .../doc/src/manual/ranch_transport.asciidoc | 194 + deps/ranch/erlang.mk | 1 + deps/ranch/examples/tcp_echo/Makefile | 3 + deps/ranch/examples/tcp_echo/README.md | 27 + deps/ranch/examples/tcp_echo/relx.config | 2 + .../examples/tcp_echo/src/echo_protocol.erl | 24 + .../examples/tcp_echo/src/tcp_echo.app.src | 15 + .../examples/tcp_echo/src/tcp_echo_app.erl | 19 + .../examples/tcp_echo/src/tcp_echo_sup.erl | 22 + deps/ranch/examples/tcp_reverse/Makefile | 3 + deps/ranch/examples/tcp_reverse/README.md | 33 + deps/ranch/examples/tcp_reverse/relx.config | 2 + .../tcp_reverse/src/reverse_protocol.erl | 73 + .../tcp_reverse/src/tcp_reverse.app.src | 15 + .../tcp_reverse/src/tcp_reverse_app.erl | 19 + .../tcp_reverse/src/tcp_reverse_sup.erl | 22 + deps/ranch/src/ranch.app.src | 9 + .../deps => deps}/ranch/src/ranch.erl | 117 +- .../ranch/src/ranch_acceptor.erl | 3 +- .../ranch/src/ranch_acceptors_sup.erl | 23 +- .../deps => deps}/ranch/src/ranch_app.erl | 2 +- .../ranch/src/ranch_conns_sup.erl | 91 +- .../ranch/src/ranch_listener_sup.erl | 10 +- .../ranch/src/ranch_protocol.erl | 2 +- .../deps => deps}/ranch/src/ranch_server.erl | 12 +- .../deps => deps}/ranch/src/ranch_ssl.erl | 42 +- .../deps => deps}/ranch/src/ranch_sup.erl | 2 +- .../deps => deps}/ranch/src/ranch_tcp.erl | 19 +- .../ranch/src/ranch_transport.erl | 2 +- {rabbitmq-server/deps => deps}/sockjs/COPYING | 0 .../deps => deps}/sockjs/Changelog | 0 .../deps => deps}/sockjs/LICENSE-APL2-Rebar | 0 .../deps => deps}/sockjs/LICENSE-EPL-OTP | 0 .../deps => deps}/sockjs/LICENSE-MIT-Mochiweb | 0 .../deps => deps}/sockjs/LICENSE-MIT-SockJS | 0 .../deps => deps}/sockjs/Makefile | 5 +- .../deps => deps}/sockjs/Makefile.orig.mk | 0 .../deps => deps}/sockjs/README.md | 0 deps/sockjs/examples/cowboy_echo.erl | 56 + .../examples/cowboy_echo_authen_callback.erl | 86 + deps/sockjs/examples/cowboy_test_server.erl | 105 + deps/sockjs/examples/echo.html | 72 + .../sockjs/examples/echo_authen_callback.html | 72 + .../examples/multiplex/cowboy_multiplex.erl | 87 + .../cowboy_multiplex_authen_callback.erl | 107 + deps/sockjs/examples/multiplex/index.html | 96 + .../multiplex/index_authen_callback.html | 109 + {rabbitmq-server/deps => deps}/sockjs/rebar | Bin .../deps => deps}/sockjs/rebar.config | 0 .../sockjs/src/mochijson2_fork.erl | 104 +- .../sockjs/src/mochinum_fork.erl | 0 .../deps => deps}/sockjs/src/sockjs.app.src | 0 .../deps => deps}/sockjs/src/sockjs.erl | 0 .../sockjs/src/sockjs_action.erl | 0 .../deps => deps}/sockjs/src/sockjs_app.erl | 0 .../sockjs/src/sockjs_cowboy_handler.erl | 9 +- .../sockjs/src/sockjs_filters.erl | 0 .../sockjs/src/sockjs_handler.erl | 0 .../deps => deps}/sockjs/src/sockjs_http.erl | 22 +- .../sockjs/src/sockjs_internal.hrl | 0 .../deps => deps}/sockjs/src/sockjs_json.erl | 0 .../sockjs/src/sockjs_multiplex.erl | 6 +- .../sockjs/src/sockjs_multiplex_channel.erl | 0 .../sockjs/src/sockjs_service.erl | 0 .../sockjs/src/sockjs_session.erl | 10 +- .../sockjs/src/sockjs_session_sup.erl | 0 .../deps => deps}/sockjs/src/sockjs_util.erl | 0 .../sockjs/src/sockjs_ws_handler.erl | 0 deps/webmachine/Emakefile | 6 + deps/webmachine/LICENSE | 178 + deps/webmachine/Makefile | 25 + deps/webmachine/Makefile.orig.mk | 24 + deps/webmachine/README.org | 66 + deps/webmachine/THANKS | 21 + deps/webmachine/demo/Makefile | 19 + deps/webmachine/demo/README | 43 + deps/webmachine/demo/priv/dispatch.conf | 3 + deps/webmachine/demo/rebar.config | 3 + .../demo/src/webmachine_demo.app.src | 17 + deps/webmachine/demo/src/webmachine_demo.erl | 42 + .../demo/src/webmachine_demo_app.erl | 20 + .../demo/src/webmachine_demo_fs_resource.erl | 159 + .../demo/src/webmachine_demo_resource.erl | 51 + .../demo/src/webmachine_demo_sup.erl | 56 + deps/webmachine/demo/start.sh | 3 + .../docs/http-headers-status-v3.png | Bin 0 -> 412634 bytes deps/webmachine/include/webmachine.hrl | 8 + .../webmachine/include}/webmachine_logger.hrl | 0 deps/webmachine/include/wm_reqdata.hrl | 8 + deps/webmachine/include/wm_reqstate.hrl | 10 + deps/webmachine/include/wm_resource.hrl | 1 + deps/webmachine/priv/templates/Makefile | 19 + deps/webmachine/priv/templates/README | 35 + .../priv/templates/priv/dispatch.conf | 2 + deps/webmachine/priv/templates/rebar.config | 3 + .../priv/templates/src/wmskel.app.src | 18 + deps/webmachine/priv/templates/src/wmskel.erl | 48 + .../priv/templates/src/wmskel_app.erl | 21 + .../priv/templates/src/wmskel_resource.erl | 13 + .../priv/templates/src/wmskel_sup.erl | 72 + deps/webmachine/priv/templates/start.sh | 3 + .../webmachine/priv/templates/wmskel.template | 35 + .../priv/trace/http-headers-status-v3.png | Bin 0 -> 412634 bytes deps/webmachine/priv/trace/wmtrace.css | 107 + deps/webmachine/priv/trace/wmtrace.js | 713 ++ deps/webmachine/priv/www/index.html | 8 + deps/webmachine/rebar | Bin 0 -> 119212 bytes deps/webmachine/rebar.config | 9 + deps/webmachine/rebar.config.script | 11 + deps/webmachine/scripts/new_webmachine.sh | 39 + deps/webmachine/src/webmachine.app.src | 8 + deps/webmachine/src/webmachine.erl | 78 + deps/webmachine/src/webmachine_app.erl | 50 + .../src/webmachine_decision_core.erl | 764 ++ deps/webmachine/src/webmachine_deps.erl | 91 + deps/webmachine/src/webmachine_dispatcher.erl | 564 ++ deps/webmachine/src/webmachine_error.erl | 75 + .../src/webmachine_error_handler.erl | 96 + .../webmachine}/src/webmachine_log.erl | 4 +- .../src/webmachine_log_handler.erl | 49 +- .../src/webmachine_logger_watcher.erl | 88 + .../src/webmachine_logger_watcher_sup.erl | 39 + deps/webmachine/src/webmachine_mochiweb.erl | 170 + deps/webmachine/src/webmachine_multipart.erl | 204 + .../src/webmachine_perf_log_handler.erl | 114 + deps/webmachine/src/webmachine_request.erl | 962 +++ deps/webmachine/src/webmachine_resource.erl | 260 + deps/webmachine/src/webmachine_router.erl | 276 + deps/webmachine/src/webmachine_sup.erl | 65 + deps/webmachine/src/webmachine_util.erl | 549 ++ deps/webmachine/src/wmtrace_resource.erl | 351 + deps/webmachine/src/wrq.erl | 338 + deps/webmachine/start-dev.sh | 3 + deps/webmachine/start.sh | 3 + deps/webmachine/www/blogs.html | 67 + deps/webmachine/www/contact.html | 48 + deps/webmachine/www/css/style-1c.css | 103 + deps/webmachine/www/css/style.css | 103 + deps/webmachine/www/debugging.html | 292 + deps/webmachine/www/diagram.html | 57 + deps/webmachine/www/dispatcher.html | 121 + deps/webmachine/www/docs.html | 58 + deps/webmachine/www/example_resources.html | 250 + deps/webmachine/www/favicon.ico | Bin 0 -> 1150 bytes deps/webmachine/www/images/WM200-crop.png | Bin 0 -> 14637 bytes .../webmachine/www/images/basho-landscape.gif | Bin 0 -> 2687 bytes .../www/images/basic-trace-decision-tab.png | Bin 0 -> 85598 bytes .../www/images/basic-trace-labeled.png | Bin 0 -> 125655 bytes .../www/images/basic-trace-request-tab.png | Bin 0 -> 28617 bytes .../www/images/basic-trace-response-tab.png | Bin 0 -> 12077 bytes deps/webmachine/www/images/bg.gif | Bin 0 -> 4969 bytes deps/webmachine/www/images/blankbox.gif | Bin 0 -> 1181 bytes deps/webmachine/www/images/chash.gif | Bin 0 -> 10589 bytes deps/webmachine/www/images/easy-ops.gif | Bin 0 -> 10991 bytes deps/webmachine/www/images/gossip4.gif | Bin 0 -> 4917 bytes deps/webmachine/www/images/halfblankbox.gif | Bin 0 -> 1045 bytes .../www/images/http-headers-status-v3.png | Bin 0 -> 412634 bytes deps/webmachine/www/images/more.gif | Bin 0 -> 38753 bytes deps/webmachine/www/images/site.gif | Bin 0 -> 862 bytes deps/webmachine/www/images/splash250.gif | Bin 0 -> 1718 bytes deps/webmachine/www/images/vclock.gif | Bin 0 -> 5759 bytes deps/webmachine/www/index.html | 73 + deps/webmachine/www/intros.html | 62 + deps/webmachine/www/mechanics.html | 108 + deps/webmachine/www/quickstart.html | 77 + deps/webmachine/www/reftrans.html | 52 + deps/webmachine/www/reqdata.html | 143 + deps/webmachine/www/resources.html | 142 + deps/webmachine/www/streambody.html | 176 + erlang.mk | 6738 ++++++++++++++++ git-revisions.txt | 34 + rabbitmq-components.mk | 284 + rabbitmq-server/README.md | 301 - rabbitmq-server/deps/amqp_client/erlang.mk | 6943 ----------------- rabbitmq-server/deps/cowboy/erlang.mk | 6029 -------------- rabbitmq-server/deps/cowlib/erlang.mk | 6056 -------------- rabbitmq-server/deps/rabbit/CONTRIBUTING.md | 63 - rabbitmq-server/deps/rabbit/Makefile | 251 - .../deps/rabbit/src/rabbit_control_pbe.erl | 92 - .../rabbit/src/rabbit_core_metrics_gc.erl | 161 - .../src/rabbit_credential_validation.erl | 53 - .../src/rabbit_credential_validator.erl | 28 - ...credential_validator_accept_everything.erl | 32 - ...edential_validator_min_password_length.erl | 56 - ...t_credential_validator_password_regexp.erl | 51 - .../deps/rabbit/src/rabbit_fhc_helpers.erl | 52 - .../deps/rabbit/src/rabbit_metrics.erl | 53 - .../deps/rabbit/src/rabbit_ssl.erl | 84 - rabbitmq-server/deps/rabbit_common/Makefile | 90 - .../deps/rabbit_common/development.pre.mk | 14 - .../include/rabbit_core_metrics.hrl | 55 - .../rabbit_common/include/rabbit_memory.hrl | 25 - .../deps/rabbit_common/mk/rabbitmq-build.mk | 33 - .../mk/rabbitmq-components.hexpm.mk | 43 - .../rabbit_common/mk/rabbitmq-early-plugin.mk | 3 - .../rabbit_common/mk/rabbitmq-early-test.mk | 90 - .../deps/rabbit_common/mk/rabbitmq-hexpm.mk | 49 - .../deps/rabbit_common/mk/rabbitmq-test.mk | 80 - .../deps/rabbit_common/src/ets_compat.erl | 94 - .../src/rabbit_amqqueue_common.erl | 42 - .../rabbit_common/src/rabbit_basic_common.erl | 50 - .../src/rabbit_channel_common.erl | 34 - .../rabbit_common/src/rabbit_core_metrics.erl | 264 - .../src/rabbit_data_coercion.erl | 47 - .../rabbit_common/src/rabbit_nodes_common.erl | 51 - .../src/rabbit_queue_collector_common.erl | 24 - .../rabbit_common/src/rabbit_ssl_options.erl | 92 - .../deps/rabbitmq_auth_backend_ldap/Makefile | 44 - .../deps/rabbitmq_auth_backend_ldap/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../rabbitmq_auth_mechanism_ssl/README.md | 95 - .../rabbitmq_auth_mechanism_ssl/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../deps/rabbitmq_event_exchange/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../deps/rabbitmq_federation/Makefile | 25 - .../deps/rabbitmq_federation/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../rabbitmq_federation_management/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../src/rabbit_federation_mgmt.erl | 155 - .../rabbitmq_jms_topic_exchange/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../deps/rabbitmq_management/Makefile | 48 - .../deps/rabbitmq_management/README.md | 17 - .../deps/rabbitmq_management/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../src/rabbit_mgmt_app.erl | 60 - .../src/rabbit_mgmt_cors.erl | 93 - .../src/rabbit_mgmt_db.erl | 757 -- .../src/rabbit_mgmt_db_cache.erl | 139 - .../src/rabbit_mgmt_db_cache_sup.erl | 35 - .../src/rabbit_mgmt_dispatcher.erl | 121 - .../src/rabbit_mgmt_stats.erl | 675 -- .../src/rabbit_mgmt_sup.erl | 51 - .../src/rabbit_mgmt_sup_sup.erl | 36 - .../src/rabbit_mgmt_wm_global_parameter.erl | 82 - .../src/rabbit_mgmt_wm_global_parameters.erl | 47 - .../src/rabbit_mgmt_wm_redirect.erl | 28 - .../src/rabbit_mgmt_wm_reset.erl | 65 - .../src/rabbit_mgmt_wm_static.erl | 64 - .../src/rabbit_mgmt_wm_user.erl | 235 - .../deps/rabbitmq_management_agent/Makefile | 29 - .../deps/rabbitmq_management_agent/erlang.mk | 6943 ----------------- .../include/rabbit_mgmt_metrics.hrl | 186 - .../rabbitmq-components.mk | 332 - .../src/exometer_slide.erl | 523 -- .../src/rabbit_mgmt_agent_config.erl | 16 - .../src/rabbit_mgmt_agent_sup.erl | 51 - .../src/rabbit_mgmt_agent_sup_sup.erl | 36 - .../src/rabbit_mgmt_data.erl | 535 -- .../src/rabbit_mgmt_gc.erl | 237 - .../src/rabbit_mgmt_metrics_collector.erl | 656 -- .../src/rabbit_mgmt_metrics_gc.erl | 184 - .../src/rabbit_mgmt_storage.erl | 65 - .../rabbitmq_management_visualiser/erlang.mk | 6943 ----------------- .../priv/www/js/visualiser.js | 3 - .../rabbitmq-components.mk | 332 - rabbitmq-server/deps/rabbitmq_mqtt/Makefile | 48 - rabbitmq-server/deps/rabbitmq_mqtt/erlang.mk | 6943 ----------------- .../deps/rabbitmq_mqtt/rabbitmq-components.mk | 332 - .../rabbit_mqtt_retained_msg_store_noop.erl | 40 - .../erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../deps/rabbitmq_sharding/erlang.mk | 6943 ----------------- .../rabbitmq_sharding/rabbitmq-components.mk | 332 - rabbitmq-server/deps/rabbitmq_shovel/Makefile | 36 - .../deps/rabbitmq_shovel/erlang.mk | 6943 ----------------- .../rabbitmq_shovel/rabbitmq-components.mk | 332 - .../deps/rabbitmq_shovel_management/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - rabbitmq-server/deps/rabbitmq_stomp/Makefile | 39 - rabbitmq-server/deps/rabbitmq_stomp/erlang.mk | 6943 ----------------- .../rabbitmq_stomp/rabbitmq-components.mk | 332 - rabbitmq-server/deps/rabbitmq_top/erlang.mk | 6943 ----------------- .../deps/rabbitmq_top/rabbitmq-components.mk | 332 - .../deps/rabbitmq_tracing/Makefile | 26 - .../deps/rabbitmq_tracing/erlang.mk | 6943 ----------------- .../rabbitmq_tracing/rabbitmq-components.mk | 332 - .../deps/rabbitmq_trust_store/Makefile | 29 - .../deps/rabbitmq_trust_store/erlang.mk | 6943 ----------------- .../rabbit_trust_store_opera_com_provider.erl | 69 - .../rabbitmq_trust_store_django/README.md | 49 - .../rabbitmq_trust_store_django/manage.py | 10 - .../rabbitmq_trust_store_django/__init__.py | 0 .../rabbitmq_trust_store_django/settings.py | 125 - .../trust_store/__init__.py | 0 .../trust_store/apps.py | 7 - .../trust_store/tests.py | 3 - .../trust_store/urls.py | 7 - .../trust_store/views.py | 41 - .../rabbitmq_trust_store_django/urls.py | 21 - .../rabbitmq_trust_store_django/wsgi.py | 16 - .../rabbitmq-components.mk | 332 - .../src/rabbit_trust_store.erl | 341 - ...abbit_trust_store_certificate_provider.erl | 24 - .../src/rabbit_trust_store_file_provider.erl | 103 - .../src/rabbit_trust_store_http_provider.erl | 100 - .../deps/rabbitmq_web_dispatch/Makefile | 20 - .../deps/rabbitmq_web_dispatch/README.md | 16 - .../deps/rabbitmq_web_dispatch/erlang.mk | 6943 ----------------- .../rabbitmq-components.mk | 332 - .../src/rabbit_cowboy_middleware.erl | 57 - .../src/rabbit_cowboy_redirect.erl | 34 - .../rabbit_web_dispatch_listing_handler.erl | 44 - .../rabbitmq_web_mqtt/LICENSE-MPL-RabbitMQ | 455 -- .../deps/rabbitmq_web_mqtt/Makefile | 33 - .../deps/rabbitmq_web_mqtt/README.md | 37 - .../deps/rabbitmq_web_mqtt/erlang.mk | 6943 ----------------- .../rabbitmq_web_mqtt/rabbitmq-components.mk | 332 - .../src/rabbit_web_mqtt_app.erl | 101 - .../src/rabbit_web_mqtt_connection_sup.erl | 59 - .../src/rabbit_web_mqtt_handler.erl | 204 - .../src/rabbit_web_mqtt_middleware.erl | 29 - .../deps/rabbitmq_web_mqtt_examples/LICENSE | 9 - .../deps/rabbitmq_web_mqtt_examples/Makefile | 23 - .../deps/rabbitmq_web_mqtt_examples/README.md | 13 - .../deps/rabbitmq_web_mqtt_examples/erlang.mk | 6943 ----------------- .../priv/bunny.html | 169 - .../rabbitmq_web_mqtt_examples/priv/echo.html | 134 - .../priv/index.html | 15 - .../priv/mqttws31.js | 2143 ----- .../rabbitmq-components.mk | 332 - .../src/rabbit_web_mqtt_examples_app.erl | 38 - .../rabbitmq_web_stomp/CODE_OF_CONDUCT.md | 44 - .../deps/rabbitmq_web_stomp/LICENSE | 5 - .../deps/rabbitmq_web_stomp/README.md | 34 - .../deps/rabbitmq_web_stomp/erlang.mk | 6943 ----------------- .../rabbitmq_web_stomp/rabbitmq-components.mk | 332 - .../src/rabbit_ws_sockjs.erl | 151 - .../CODE_OF_CONDUCT.md | 44 - .../CONTRIBUTING.md | 38 - .../LICENSE-MPL-RabbitMQ | 455 -- .../rabbitmq_web_stomp_examples/erlang.mk | 6943 ----------------- .../priv/bunny.png | Bin 38296 -> 0 bytes .../rabbitmq_web_stomp_examples/priv/main.css | 38 - .../priv/pencil.cur | Bin 2238 -> 0 bytes .../rabbitmq-components.mk | 332 - rabbitmq-server/erlang.mk | 6943 ----------------- rabbitmq-server/git-revisions.txt | 35 - rabbitmq-server/plugins.mk | 1 - rabbitmq-server/rabbitmq-components.mk | 332 - .../rabbitmq-script-wrapper | 8 +- .../rabbitmq-server-ha.ocf | 41 +- .../scripts => scripts}/rabbitmq-server.ocf | 28 +- scripts/travis_test_ocf_ra.sh | 30 + upgrade/Makefile | 109 + upgrade/README.md | 64 + upgrade/config/enabled_plugins | 1 + upgrade/config/rabbitmq.config | 1 + upgrade/scripts/upgrade-from-3.5-helpers.sh | 80 + upgrade/scripts/upgrade-from.sh | 10 + upgrade/scripts/upgrade-helpers.sh | 5 + upgrade/scripts/upgrade-to-3.6-helpers.sh | 101 + upgrade/scripts/upgrade-to-3.7-helpers.sh | 104 + upgrade/scripts/upgrade-to.sh | 8 + 1383 files changed, 198893 insertions(+), 224205 deletions(-) create mode 100644 .gitignore rename rabbitmq-server/CODE_OF_CONDUCT.md => CODE_OF_CONDUCT.md (100%) rename rabbitmq-server/CONTRIBUTING.md => CONTRIBUTING.md (100%) rename rabbitmq-server/LICENSE => LICENSE (100%) rename rabbitmq-server/LICENSE-APACHE2-ExplorerCanvas => LICENSE-APACHE2-ExplorerCanvas (100%) rename rabbitmq-server/LICENSE-APL2-Rebar => LICENSE-APL2-Rebar (100%) rename rabbitmq-server/LICENSE-APL2-Stomp-Websocket => LICENSE-APL2-Stomp-Websocket (100%) rename rabbitmq-server/LICENSE-BSD-base64js => LICENSE-BSD-base64js (100%) rename rabbitmq-server/LICENSE-BSD-glMatrix => LICENSE-BSD-glMatrix (100%) rename rabbitmq-server/LICENSE-EPL-OTP => LICENSE-EPL-OTP (100%) rename rabbitmq-server/LICENSE-MIT-EJS10 => LICENSE-MIT-EJS10 (100%) rename rabbitmq-server/LICENSE-MIT-Erlware-Commons => LICENSE-MIT-Erlware-Commons (100%) rename rabbitmq-server/LICENSE-MIT-Flot => LICENSE-MIT-Flot (100%) rename rabbitmq-server/LICENSE-MIT-Mochi => LICENSE-MIT-Mochi (100%) rename rabbitmq-server/LICENSE-MIT-Mochiweb => LICENSE-MIT-Mochiweb (100%) rename rabbitmq-server/LICENSE-MIT-Sammy060 => LICENSE-MIT-Sammy060 (100%) rename rabbitmq-server/LICENSE-MIT-SockJS => LICENSE-MIT-SockJS (100%) rename rabbitmq-server/LICENSE-MIT-jQuery164 => LICENSE-MIT-jQuery164 (100%) rename rabbitmq-server/LICENSE-MPL-RabbitMQ => LICENSE-MPL-RabbitMQ (100%) rename rabbitmq-server/LICENSE-MPL2 => LICENSE-MPL2 (100%) rename rabbitmq-server/Makefile => Makefile (82%) create mode 100644 debian/dirs delete mode 100644 debian/gbp.conf create mode 100644 debian/patches/native-code-location.patch create mode 100644 debian/patches/series create mode 100755 debian/postinst create mode 100644 debian/postrm.in delete mode 100644 debian/rabbitmq-env.conf delete mode 100755 debian/rabbitmq-script-wrapper delete mode 100755 debian/rabbitmq-server-wait delete mode 100644 debian/rabbitmq-server.dirs create mode 100644 debian/rabbitmq-server.docs delete mode 100644 debian/rabbitmq-server.install delete mode 100644 debian/rabbitmq-server.links create mode 100644 debian/rabbitmq-server.manpages delete mode 100644 debian/rabbitmq-server.postinst delete mode 100644 debian/rabbitmq-server.postrm delete mode 100644 debian/source.lintian-overrides rename {rabbitmq-server/deps => deps}/amqp_client/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps => deps}/amqp_client/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/amqp_client/Makefile (74%) rename {rabbitmq-server/deps => deps}/amqp_client/README.in (100%) rename {rabbitmq-server/deps => deps}/amqp_client/ci/test.sh (100%) rename {rabbitmq-server/deps => deps}/amqp_client/ci/test.yml (100%) rename {rabbitmq-server/deps/ranch => deps/amqp_client}/erlang.mk (94%) rename {rabbitmq-server/deps => deps}/amqp_client/include/amqp_client.hrl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/include/amqp_client_internal.hrl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/include/amqp_gen_consumer_spec.hrl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/include/rabbit_routing_prefixes.hrl (100%) rename {rabbitmq-server/deps/rabbitmq_amqp1_0 => deps/amqp_client}/rabbitmq-components.mk (83%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_auth_mechanisms.erl (96%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_channel.erl (96%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_channel_sup.erl (98%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_channel_sup_sup.erl (91%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_channels_manager.erl (97%) create mode 100644 deps/amqp_client/src/amqp_client.app.src rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_client.erl (77%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_connection.erl (98%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_connection_sup.erl (96%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_connection_type_sup.erl (98%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_direct_connection.erl (94%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_direct_consumer.erl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_gen_connection.erl (95%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_gen_consumer.erl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_main_reader.erl (98%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_network_connection.erl (96%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_rpc_client.erl (99%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_rpc_server.erl (98%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_selective_consumer.erl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_sup.erl (95%) rename {rabbitmq-server/deps => deps}/amqp_client/src/amqp_uri.erl (93%) rename {rabbitmq-server/deps => deps}/amqp_client/src/overview.edoc.in (100%) rename {rabbitmq-server/deps => deps}/amqp_client/src/rabbit_routing_util.erl (100%) rename {rabbitmq-server/deps => deps}/amqp_client/src/uri_parser.erl (96%) rename {rabbitmq-server/deps => deps}/cowboy/AUTHORS (100%) rename {rabbitmq-server/deps => deps}/cowboy/CHANGELOG.md (99%) rename {rabbitmq-server/deps => deps}/cowboy/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/cowboy/LICENSE (100%) rename {rabbitmq-server/deps => deps}/cowboy/Makefile (97%) rename {rabbitmq-server/deps => deps}/cowboy/README.md (100%) rename {rabbitmq-server/deps => deps}/cowboy/ROADMAP.md (100%) rename {rabbitmq-server/deps => deps}/cowboy/all.sh (100%) rename {rabbitmq-server/deps => deps}/cowboy/circle.yml (94%) create mode 100644 deps/cowboy/erlang.mk rename {rabbitmq-server/deps => deps}/cowboy/rebar.config (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy.app.src (91%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_app.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_bstr.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_clock.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_handler.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_http.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_http_handler.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_loop_handler.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_middleware.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_protocol.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_req.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_rest.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_router.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_spdy.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_static.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_sub_protocol.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_sup.erl (100%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_websocket.erl (99%) rename {rabbitmq-server/deps => deps}/cowboy/src/cowboy_websocket_handler.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/AUTHORS (78%) rename {rabbitmq-server/deps => deps}/cowlib/CHANGELOG.md (64%) rename {rabbitmq-server/deps => deps}/cowlib/LICENSE (100%) rename {rabbitmq-server/deps => deps}/cowlib/Makefile (79%) rename {rabbitmq-server/deps => deps}/cowlib/README.md (100%) create mode 100755 deps/cowlib/all.sh create mode 100644 deps/cowlib/build.config create mode 100644 deps/cowlib/erlang.mk rename {rabbitmq-server/deps => deps}/cowlib/include/cow_inline.hrl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_cookie.erl (97%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_date.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_http.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_http_hd.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_http_te.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_mimetypes.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_mimetypes.erl.src (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_multipart.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_qs.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_spdy.erl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cow_spdy.hrl (100%) rename {rabbitmq-server/deps => deps}/cowlib/src/cowlib.app.src (89%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-APACHE2-ExplorerCanvas (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-APL2-Rebar (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-APL2-Stomp-Websocket (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-BSD-base64js (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-BSD-glMatrix (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-EPL-OTP (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-EJS10 (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-Erlware-Commons (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-Flot (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-Mochi (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-Mochiweb (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-Sammy060 (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-SockJS (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MIT-jQuery164 (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/licensing/LICENSE-MPL2 (100%) rename {rabbitmq-server/deps => deps}/licensing/license_info_rabbitmq_codegen (100%) rename {rabbitmq-server/deps => deps}/licensing/license_info_rabbitmq_management (100%) rename {rabbitmq-server/deps => deps}/licensing/license_info_rabbitmq_management_visualiser (100%) create mode 100644 deps/mochiweb/.editorconfig create mode 100644 deps/mochiweb/CHANGES.md rename rabbitmq-server/deps/rabbit/LICENSE-MIT-Mochi => deps/mochiweb/LICENSE (100%) create mode 100644 deps/mochiweb/Makefile create mode 100644 deps/mochiweb/Makefile.orig.mk create mode 100644 deps/mochiweb/README create mode 100644 deps/mochiweb/examples/hmac_api/README create mode 100644 deps/mochiweb/examples/hmac_api/hmac_api.hrl create mode 100644 deps/mochiweb/examples/hmac_api/hmac_api_client.erl create mode 100644 deps/mochiweb/examples/hmac_api/hmac_api_lib.erl create mode 100644 deps/mochiweb/examples/https/https_store.erl create mode 100644 deps/mochiweb/examples/https/server_cert.pem create mode 100644 deps/mochiweb/examples/https/server_key.pem create mode 100644 deps/mochiweb/examples/keepalive/keepalive.erl create mode 100644 deps/mochiweb/examples/websocket/index.html create mode 100644 deps/mochiweb/examples/websocket/websocket.erl create mode 100644 deps/mochiweb/include/internal.hrl create mode 100755 deps/mochiweb/rebar create mode 100644 deps/mochiweb/rebar.config create mode 100755 deps/mochiweb/scripts/entities.erl create mode 100644 deps/mochiweb/src/mochifmt.erl create mode 100644 deps/mochiweb/src/mochifmt_records.erl create mode 100644 deps/mochiweb/src/mochifmt_std.erl create mode 100644 deps/mochiweb/src/mochiglobal.erl create mode 100644 deps/mochiweb/src/mochihex.erl create mode 100644 deps/mochiweb/src/mochijson.erl create mode 100644 deps/mochiweb/src/mochijson2.erl create mode 100644 deps/mochiweb/src/mochilists.erl create mode 100644 deps/mochiweb/src/mochilogfile2.erl create mode 100644 deps/mochiweb/src/mochinum.erl create mode 100644 deps/mochiweb/src/mochitemp.erl create mode 100644 deps/mochiweb/src/mochiutf8.erl create mode 100644 deps/mochiweb/src/mochiweb.app.src create mode 100644 deps/mochiweb/src/mochiweb.erl create mode 100644 deps/mochiweb/src/mochiweb_acceptor.erl create mode 100644 deps/mochiweb/src/mochiweb_base64url.erl create mode 100644 deps/mochiweb/src/mochiweb_charref.erl create mode 100644 deps/mochiweb/src/mochiweb_clock.erl create mode 100644 deps/mochiweb/src/mochiweb_cookies.erl create mode 100644 deps/mochiweb/src/mochiweb_cover.erl create mode 100644 deps/mochiweb/src/mochiweb_echo.erl create mode 100644 deps/mochiweb/src/mochiweb_headers.erl create mode 100644 deps/mochiweb/src/mochiweb_html.erl create mode 100644 deps/mochiweb/src/mochiweb_http.erl create mode 100644 deps/mochiweb/src/mochiweb_io.erl create mode 100644 deps/mochiweb/src/mochiweb_mime.erl create mode 100644 deps/mochiweb/src/mochiweb_multipart.erl create mode 100644 deps/mochiweb/src/mochiweb_request.erl create mode 100644 deps/mochiweb/src/mochiweb_response.erl create mode 100644 deps/mochiweb/src/mochiweb_session.erl create mode 100644 deps/mochiweb/src/mochiweb_socket.erl create mode 100644 deps/mochiweb/src/mochiweb_socket_server.erl rename {rabbitmq-server/deps/rabbit_common => deps/mochiweb}/src/mochiweb_util.erl (96%) create mode 100644 deps/mochiweb/src/mochiweb_websocket.erl create mode 100644 deps/mochiweb/src/reloader.erl create mode 100644 deps/mochiweb/support/templates/mochiwebapp.template create mode 100755 deps/mochiweb/support/templates/mochiwebapp_skel/bench.sh create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/priv/www/index.html create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/rebar.config create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.app.src create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.erl create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_app.erl create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_deps.erl create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_sup.erl create mode 100644 deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_web.erl create mode 100755 deps/mochiweb/support/templates/mochiwebapp_skel/start-dev.sh create mode 100644 deps/mochiweb/support/test-materials/test_ssl_cert.pem create mode 100644 deps/mochiweb/support/test-materials/test_ssl_key.pem rename {rabbitmq-server/deps => deps}/rabbit/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbit/INSTALL (100%) rename {rabbitmq-server/deps => deps}/rabbit/LICENSE (100%) create mode 100644 deps/rabbit/LICENSE-MIT-Mochi rename {rabbitmq-server/deps => deps}/rabbit/LICENSE-MPL-RabbitMQ (100%) create mode 100644 deps/rabbit/Makefile create mode 100644 deps/rabbit/README rename {rabbitmq-server/deps => deps}/rabbit/README.md (97%) rename {rabbitmq-server/deps => deps}/rabbit/check_xref (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/README-for-packages (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/examples-to-end.xsl (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/html-to-website-xml.xsl (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-echopid.xml (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-env.conf.5.xml (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-plugins.1.xml (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-server.1.xml (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-server.service.example (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq-service.xml (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmq.config.example (94%) rename {rabbitmq-server/deps => deps}/rabbit/docs/rabbitmqctl.1.xml (92%) rename {rabbitmq-server/deps => deps}/rabbit/docs/remove-namespaces.xsl (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/set_rabbitmq_policy.sh.example (100%) rename {rabbitmq-server/deps => deps}/rabbit/docs/usage.xsl (100%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/erlang.mk (92%) rename {rabbitmq-server/deps => deps}/rabbit/include/gm_specs.hrl (94%) rename {rabbitmq-server/deps => deps}/rabbit/include/rabbit_cli.hrl (97%) rename {rabbitmq-server/deps => deps}/rabbit/quickcheck (100%) rename {rabbitmq-server/deps => deps}/rabbit/rabbitmq-components.mk (83%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-defaults (76%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-defaults.bat (100%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-echopid.bat (100%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-env (94%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-env.bat (95%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-plugins (100%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-plugins.bat (100%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-server (82%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-server.bat (92%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmq-service.bat (89%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmqctl (100%) rename {rabbitmq-server/deps => deps}/rabbit/scripts/rabbitmqctl.bat (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/background_gc.erl (74%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/delegate.erl (72%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/delegate_sup.erl (65%) rename {rabbitmq-server/deps => deps}/rabbit/src/dtree.erl (99%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/file_handle_cache.erl (98%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/file_handle_cache_stats.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/gatherer.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/gm.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/lqueue.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/mirrored_supervisor_sups.erl (100%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/mnesia_sync.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/pg_local.erl (100%) create mode 100644 deps/rabbit/src/rabbit.app.src rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit.erl (91%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_access_control.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_alarm.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_amqqueue_process.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_amqqueue_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_amqqueue_sup_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_auth_mechanism_amqplain.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_auth_mechanism_cr_demo.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_auth_mechanism_plain.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_autoheal.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_binding.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_boot_steps.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_channel_sup.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_channel_sup_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_cli.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_client_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_connection_helper_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_connection_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_control_main.erl (91%) create mode 100644 deps/rabbit/src/rabbit_control_pbe.erl rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_dead_letter.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_diagnostics.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_direct.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_disk_monitor.erl (86%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_epmd_monitor.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_error_logger.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_error_logger_file_h.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_parameters.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_type_direct.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_type_fanout.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_type_headers.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_type_invalid.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_exchange_type_topic.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_file.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_framing.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_guid.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_hipe.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_limiter.erl (99%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/rabbit_log.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_memory_monitor.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_coordinator.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_master.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_misc.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_mode.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_mode_all.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_mode_exactly.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_mode_nodes.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_slave.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mirror_queue_sync.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mnesia.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_mnesia_rename.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_msg_file.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_msg_store.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_msg_store_ets_index.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_msg_store_gc.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_node_monitor.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_parameter_validation.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_password.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_password_hashing_md5.erl (93%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_password_hashing_sha256.erl (92%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_password_hashing_sha512.erl (92%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/rabbit_pbe.erl (92%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_plugins.erl (62%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_plugins_main.erl (89%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_policies.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_policy.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_prelaunch.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_prequeue.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_priority_queue.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_consumers.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_index.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_location_client_local.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_location_min_masters.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_location_random.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_location_validator.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_queue_master_location_misc.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_recovery_terms.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_registry.erl (98%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/rabbit_resource_monitor_misc.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_restartable_sup.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_router.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_runtime_parameters.erl (80%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_sasl_report_file_h.erl (98%) rename rabbitmq-server/deps/rabbit_common/src/rabbit_cert_info.erl => deps/rabbit/src/rabbit_ssl.erl (84%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_sup.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_table.erl (84%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_trace.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_upgrade.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_upgrade_functions.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_variable_queue.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_version.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_vhost.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit/src/rabbit_vm.erl (89%) rename {rabbitmq-server/deps => deps}/rabbit/src/supervised_lifecycle.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit/src/tcp_listener.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit/src/tcp_listener_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit/src/truncate.erl (98%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/vm_memory_monitor.erl (67%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/worker_pool.erl (99%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/worker_pool_sup.erl (97%) rename {rabbitmq-server/deps/rabbit_common => deps/rabbit}/src/worker_pool_worker.erl (78%) rename {rabbitmq-server/deps => deps}/rabbit_common/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_amqp1_0 => deps/rabbit_common}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/LICENSE-MIT-Erlware-Commons (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/LICENSE-MPL-RabbitMQ (100%) rename rabbitmq-server/deps/rabbit_common/development.post.mk => deps/rabbit_common/Makefile (56%) rename {rabbitmq-server/deps => deps}/rabbit_common/codegen.py (100%) rename {rabbitmq-server/deps/rabbitmq_amqp1_0 => deps/rabbit_common}/erlang.mk (92%) rename {rabbitmq-server/deps => deps}/rabbit_common/include/old_builtin_types.hrl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/include/rabbit.hrl (93%) rename {rabbitmq-server/deps => deps}/rabbit_common/include/rabbit_misc.hrl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/include/rabbit_msg_store.hrl (91%) create mode 100644 deps/rabbit_common/mk/rabbitmq-build.mk rename {rabbitmq-server/deps/amqp_client => deps/rabbit_common/mk}/rabbitmq-components.mk (83%) rename {rabbitmq-server/deps => deps}/rabbit_common/mk/rabbitmq-dist.mk (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/mk/rabbitmq-plugin.mk (66%) rename {rabbitmq-server/deps => deps}/rabbit_common/mk/rabbitmq-run.mk (95%) rename {rabbitmq-server/deps => deps}/rabbit_common/mk/rabbitmq-tools.mk (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/app_utils.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/code_version.erl (93%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/credit_flow.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/ec_semver.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/ec_semver_parser.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/gen_server2.erl (93%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/mirrored_supervisor.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/mochijson2.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/mochinum.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/pmon.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/priority_queue.erl (99%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_amqqueue.erl (92%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_auth_backend_dummy.erl (96%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_auth_backend_internal.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_auth_mechanism.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_authn_backend.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_authz_backend.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_backing_queue.erl (98%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_basic.erl (90%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_binary_generator.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_binary_parser.erl (93%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_channel.erl (98%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_channel_interceptor.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_command_assembler.erl (98%) create mode 100644 deps/rabbit_common/src/rabbit_common.app.src rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_control_misc.erl (98%) rename rabbitmq-server/deps/rabbit/src/term_to_binary_compat.erl => deps/rabbit_common/src/rabbit_data_coercion.erl (72%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_error_logger_handler.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_event.erl (98%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_exchange_decorator.erl (98%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_exchange_type.erl (97%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_health_check.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_heartbeat.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_misc.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_msg_store_index.erl (96%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_net.erl (90%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_networking.erl (81%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_nodes.erl (87%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_password_hashing.erl (91%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_policy_validator.erl (92%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_queue_collector.erl (95%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_queue_decorator.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_queue_master_locator.erl (92%) rename {rabbitmq-server/deps/rabbit => deps/rabbit_common}/src/rabbit_reader.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_runtime_parameter.erl (94%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_types.erl (97%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rabbit_writer.erl (91%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/rand_compat.erl (100%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/ssl_compat.erl (95%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/supervisor2.erl (99%) rename {rabbitmq-server/deps => deps}/rabbit_common/src/time_compat.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_auth_backend_ldap => deps/rabbitmq_amqp1_0}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/Makefile (75%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/README.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/codegen.py (100%) rename {rabbitmq-server/deps/rabbit => deps/rabbitmq_amqp1_0}/erlang.mk (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/include/rabbit_amqp1_0.hrl (100%) rename {rabbitmq-server/deps/rabbit_common/mk => deps/rabbitmq_amqp1_0}/rabbitmq-components.mk (83%) rename {rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0 => deps/rabbitmq_amqp1_0/spec}/messaging.xml (100%) rename {rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0 => deps/rabbitmq_amqp1_0/spec}/security.xml (100%) rename {rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0 => deps/rabbitmq_amqp1_0/spec}/transactions.xml (100%) rename {rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0 => deps/rabbitmq_amqp1_0/spec}/transport.xml (100%) rename {rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0 => deps/rabbitmq_amqp1_0/spec}/types.xml (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl (91%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl (99%) create mode 100644 deps/rabbitmq_amqp1_0/src/rabbitmq_amqp1_0.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl => deps/rabbitmq_auth_backend_ldap}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_auth_backend_ldap/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/README-authorisation.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/README-tests.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/README.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/Vagrantfile (100%) create mode 100644 deps/rabbitmq_auth_backend_ldap/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/global.ldif (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/memberof_init.ldif (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/refint_1.ldif (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/refint_2.ldif (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/seed.sh (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/example/setup.sh (100%) create mode 100644 deps/rabbitmq_auth_backend_ldap/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl (88%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl (91%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl (94%) create mode 100644 deps/rabbitmq_auth_backend_ldap/src/rabbitmq_auth_backend_ldap.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_auth_mechanism_ssl/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_codegen => deps/rabbitmq_auth_mechanism_ssl}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_mechanism_ssl/Makefile (59%) create mode 100644 deps/rabbitmq_auth_mechanism_ssl/README.md create mode 100644 deps/rabbitmq_auth_mechanism_ssl/erlang.mk create mode 100644 deps/rabbitmq_auth_mechanism_ssl/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl (94%) create mode 100644 deps/rabbitmq_auth_mechanism_ssl/src/rabbitmq_auth_mechanism_ssl.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_consistent_hash_exchange => deps/rabbitmq_codegen}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/Makefile (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/README.extensions.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/amqp-rabbitmq-0.8.json (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/amqp-rabbitmq-0.9.1.json (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/amqp_codegen.py (87%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/credit_extension.json (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/demo_extension.json (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_codegen/license_info (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_event_exchange => deps/rabbitmq_consistent_hash_exchange}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/Makefile (66%) rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/README.md (100%) create mode 100644 deps/rabbitmq_consistent_hash_exchange/erlang.mk create mode 100644 deps/rabbitmq_consistent_hash_exchange/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl (95%) create mode 100644 deps/rabbitmq_consistent_hash_exchange/src/rabbitmq_consistent_hash_exchange.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_federation => deps/rabbitmq_event_exchange}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/Makefile (66%) rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/README.md (70%) create mode 100644 deps/rabbitmq_event_exchange/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/examples/java/QueueEvents.java (100%) create mode 100644 deps/rabbitmq_event_exchange/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl (98%) create mode 100644 deps/rabbitmq_event_exchange/src/rabbitmq_event_exchange.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_federation/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_federation_management => deps/rabbitmq_federation}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_federation/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_federation/README-hacking (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/README.md (100%) create mode 100644 deps/rabbitmq_federation/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_federation/etc/rabbit-test.sh (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/etc/setup-rabbit-test.sh (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/include/rabbit_federation.hrl (100%) create mode 100644 deps/rabbitmq_federation/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_app.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_db.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_event.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_exchange.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_exchange_link.erl (86%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl (95%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_link_sup.erl (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_link_util.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_parameters.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_queue.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_queue_link.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_status.erl (68%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_sup.erl (86%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_upstream.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation/src/rabbit_federation_util.erl (97%) create mode 100644 deps/rabbitmq_federation/src/rabbitmq_federation.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_jms_topic_exchange => deps/rabbitmq_federation_management}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-APACHE2-ExplorerCanvas (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-BSD-base64js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-MIT-EJS10 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-MIT-Flot (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-MIT-Sammy060 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-MIT-jQuery164 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/Makefile (57%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/README.md (95%) create mode 100644 deps/rabbitmq_federation_management/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/priv/www/js/federation.js (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstream.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstreams.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs (83%) create mode 100644 deps/rabbitmq_federation_management/rabbitmq-components.mk create mode 100644 deps/rabbitmq_federation_management/src/rabbit_federation_mgmt.erl create mode 100644 deps/rabbitmq_federation_management/src/rabbitmq_federation_management.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_management => deps/rabbitmq_jms_topic_exchange}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/LICENSES.txt (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/Makefile (64%) rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/README.md (97%) create mode 100644 deps/rabbitmq_jms_topic_exchange/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/include/rabbit_jms_topic_exchange.hrl (100%) create mode 100644 deps/rabbitmq_jms_topic_exchange/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl (100%) create mode 100644 deps/rabbitmq_jms_topic_exchange/src/rabbitmq_jms_topic_exchange.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_management_agent => deps/rabbitmq_management}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE (82%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-APACHE2-ExplorerCanvas (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-BSD-base64js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-MIT-EJS10 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-MIT-Flot (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-MIT-Sammy060 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-MIT-jQuery164 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/LICENSE-MPL-RabbitMQ (100%) create mode 100644 deps/rabbitmq_management/Makefile create mode 100644 deps/rabbitmq_management/README.md rename {rabbitmq-server/deps => deps}/rabbitmq_management/bin/rabbitmqadmin (91%) create mode 100644 deps/rabbitmq_management/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_management/include/rabbit_mgmt.hrl (81%) create mode 100644 deps/rabbitmq_management/include/rabbit_mgmt_event_collector.hrl create mode 100644 deps/rabbitmq_management/include/rabbit_mgmt_metrics.hrl create mode 100644 deps/rabbitmq_management/include/rabbit_mgmt_test.hrl rename {rabbitmq-server/deps => deps}/rabbitmq_management/license_info (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/api/index.html (90%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/cli/index.html (81%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/css/evil.css (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/css/main.css (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/doc/stats.html (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/favicon.ico (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/bg-binary.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/bg-green-dark.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/bg-red-dark.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/bg-red.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/bg-yellow-dark.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/collapse.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/expand.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/img/rabbitmqlogo.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/index.html (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/base64.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/charts.js (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/dispatcher.js (95%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/ejs.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/ejs.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/excanvas.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/excanvas.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/formatters.js (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/global.js (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/help.js (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery-1.6.4.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery-1.6.4.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery.flot.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery.flot.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery.flot.time.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/jquery.flot.time.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/json2.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/main.js (91%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/prefs.js (79%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/sammy.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/sammy.min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/404.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/add-binding.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/binary.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/bindings.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/channel.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/channels.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/cluster-name.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/columns-options.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/connection.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/connections.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/consumers.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/error-popup.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/exchange.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/import-succeeded.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/layout.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/login.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/memory-bar.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/memory-table.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/memory.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/messages.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/node.ejs (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/overview.ejs (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/partition.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/paths.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/permissions.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/policies.ejs (91%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/policy.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/publish.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/queue.ejs (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/queues.ejs (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/rate-options.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/registry.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/status.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/user.ejs (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/users.ejs (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/vhost.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs (100%) create mode 100644 deps/rabbitmq_management/rabbitmq-components.mk create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_app.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_channel_stats_collector.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_cors.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_db.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_event_collector.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_event_collector_utils.erl rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_extension.erl (63%) rename {rabbitmq-server/deps/rabbitmq_management_agent => deps/rabbitmq_management}/src/rabbit_mgmt_format.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl (96%) create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_queue_stats_collector.erl rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl (94%) create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_stats.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_stats_gc.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_stats_tables.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_sup.erl create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_sup_sup.erl rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_util.erl (66%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl (73%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl (71%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl (67%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl (67%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl (71%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl (63%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl (71%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl (67%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl (57%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl (62%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl (78%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl (58%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl (64%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl (52%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_node.erl (69%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl (70%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl (77%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl (71%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl (69%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl (79%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl (63%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl (66%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl (65%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl (68%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl (69%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl (61%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl (67%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl (69%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl (51%) create mode 100644 deps/rabbitmq_management/src/rabbit_mgmt_wm_user.erl rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_users.erl (65%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl (74%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl (55%) rename {rabbitmq-server/deps => deps}/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl (59%) create mode 100644 deps/rabbitmq_management/src/rabbitmq_management.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_management_visualiser => deps/rabbitmq_management_agent}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/LICENSE-MPL-RabbitMQ (100%) create mode 100644 deps/rabbitmq_management_agent/Makefile create mode 100644 deps/rabbitmq_management_agent/erlang.mk create mode 100644 deps/rabbitmq_management_agent/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl (87%) rename rabbitmq-server/deps/rabbitmq_management_agent/include/rabbit_mgmt_records.hrl => deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup.erl (62%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl (79%) create mode 100644 deps/rabbitmq_management_agent/src/rabbitmq_management_agent.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_mqtt => deps/rabbitmq_management_visualiser}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/LICENSE-BSD-glMatrix (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/Makefile (64%) rename rabbitmq-server/deps/rabbitmq_management_visualiser/README.md => deps/rabbitmq_management_visualiser/README (71%) create mode 100644 deps/rabbitmq_management_visualiser/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/license_info (100%) create mode 100644 deps/rabbitmq_management_visualiser/priv/www/js/visualiser.js rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/index.html (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix-min.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/main.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/model.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/octtree.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/priv/www/visualiser/js/physics.js (100%) create mode 100644 deps/rabbitmq_management_visualiser/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl (57%) rename {rabbitmq-server/deps => deps}/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl (81%) create mode 100644 deps/rabbitmq_management_visualiser/src/rabbitmq_management_visualiser.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_recent_history_exchange => deps/rabbitmq_mqtt}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_mqtt/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/README.md (100%) create mode 100644 deps/rabbitmq_mqtt/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/include/rabbit_mqtt.hrl (80%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/include/rabbit_mqtt_frame.hrl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/include/rabbit_mqtt_retained_msg_store.hrl (100%) create mode 100644 deps/rabbitmq_mqtt/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt.erl (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl (86%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl (81%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl (81%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_dets.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_ets.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_retainer.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl (82%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_util.erl (89%) rename {rabbitmq-server/deps => deps}/rabbitmq_mqtt/src/rabbit_mqtt_vhost_event_handler.erl (100%) create mode 100644 deps/rabbitmq_mqtt/src/rabbitmq_mqtt.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_sharding => deps/rabbitmq_recent_history_exchange}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/LICENSE.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/Makefile (65%) rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/README.md (100%) create mode 100644 deps/rabbitmq_recent_history_exchange/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/etc/rabbit-hare.config (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/etc/rabbit-test.config (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/include/rabbit_recent_history.hrl (100%) create mode 100644 deps/rabbitmq_recent_history_exchange/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl (99%) create mode 100644 deps/rabbitmq_recent_history_exchange/src/rabbitmq_recent_history_exchange.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_shovel => deps/rabbitmq_sharding}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/LICENSE-MPL2 (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/Makefile (65%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/README.extra.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/README.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/docs/sharded_queues.png (100%) create mode 100644 deps/rabbitmq_sharding/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/etc/rabbit-hare.config (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/etc/rabbit-test.config (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/etc/rkey.sh (100%) create mode 100644 deps/rabbitmq_sharding/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_shard.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_sharding/src/rabbit_sharding_util.erl (96%) create mode 100644 deps/rabbitmq_sharding/src/rabbitmq_sharding.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_shovel_management => deps/rabbitmq_shovel}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_shovel/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/README.md (92%) create mode 100644 deps/rabbitmq_shovel/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/include/rabbit_shovel.hrl (100%) create mode 100644 deps/rabbitmq_shovel/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel.erl (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_config.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl (95%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_parameters.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_status.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_sup.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_util.erl (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_worker.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl (96%) create mode 100644 deps/rabbitmq_shovel/src/rabbitmq_shovel.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_stomp => deps/rabbitmq_shovel_management}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/Makefile (56%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/README.md (94%) create mode 100644 deps/rabbitmq_shovel_management/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/priv/www/js/shovel.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovel.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovels.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/priv/www/js/tmpl/shovels.ejs (100%) create mode 100644 deps/rabbitmq_shovel_management/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl (89%) create mode 100644 deps/rabbitmq_shovel_management/src/rabbitmq_shovel_management.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_top => deps/rabbitmq_stomp}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_stomp/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/NOTES (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/README.md (100%) create mode 100644 deps/rabbitmq_stomp/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_recv.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_client.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_service.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send_many.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/perl/rabbitmq_stomp_slow_recv.pl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/cb-receiver.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/cb-sender.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/cb-slow-receiver.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/persistent-receiver.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/persistent-sender.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/topic-broadcast-receiver.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/topic-broadcast-with-unsubscribe.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/examples/ruby/topic-sender.rb (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/include/rabbit_stomp.hrl (67%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/include/rabbit_stomp_frame.hrl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/include/rabbit_stomp_headers.hrl (100%) create mode 100644 deps/rabbitmq_stomp/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp.erl (85%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_frame.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_processor.erl (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_reader.erl (79%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_sup.erl (97%) rename {rabbitmq-server/deps => deps}/rabbitmq_stomp/src/rabbit_stomp_util.erl (98%) create mode 100644 deps/rabbitmq_stomp/src/rabbitmq_stomp.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_top/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_tracing => deps/rabbitmq_top}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/Makefile (74%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/README.md (100%) create mode 100644 deps/rabbitmq_top/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_top/priv/www/js/tmpl/ets_tables.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/priv/www/js/tmpl/process.ejs (89%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/priv/www/js/tmpl/processes.ejs (91%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/priv/www/js/top.js (87%) create mode 100644 deps/rabbitmq_top/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_app.erl (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_extension.erl (79%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_sup.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_util.erl (82%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl (61%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_wm_process.erl (88%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_wm_processes.erl (62%) rename {rabbitmq-server/deps => deps}/rabbitmq_top/src/rabbit_top_worker.erl (92%) create mode 100644 deps/rabbitmq_top/src/rabbitmq_top.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_trust_store => deps/rabbitmq_tracing}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_tracing/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/README.md (100%) create mode 100644 deps/rabbitmq_tracing/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/priv/www/js/tmpl/traces.ejs (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/priv/www/js/tracing.js (100%) create mode 100644 deps/rabbitmq_tracing/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_app.erl (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_consumer.erl (99%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl (94%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_files.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl (63%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_sup.erl (96%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_traces.erl (98%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_util.erl (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl (72%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl (72%) create mode 100644 deps/rabbitmq_tracing/src/rabbitmq_tracing.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_trust_store/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_web_dispatch => deps/rabbitmq_trust_store}/CONTRIBUTING.md (100%) create mode 100644 deps/rabbitmq_trust_store/Makefile rename {rabbitmq-server/deps => deps}/rabbitmq_trust_store/README.md (64%) create mode 100644 deps/rabbitmq_trust_store/erlang.mk create mode 100644 deps/rabbitmq_trust_store/rabbitmq-components.mk create mode 100644 deps/rabbitmq_trust_store/src/rabbit_trust_store.erl rename {rabbitmq-server/deps => deps}/rabbitmq_trust_store/src/rabbit_trust_store_app.erl (57%) rename {rabbitmq-server/deps => deps}/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl (75%) create mode 100644 deps/rabbitmq_trust_store/src/rabbitmq_trust_store.app.src rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt => deps/rabbitmq_web_dispatch}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/LICENSE (100%) create mode 100644 deps/rabbitmq_web_dispatch/Makefile create mode 100644 deps/rabbitmq_web_dispatch/README.md create mode 100644 deps/rabbitmq_web_dispatch/erlang.mk create mode 100644 deps/rabbitmq_web_dispatch/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl (60%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl (93%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl (76%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl (59%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl (96%) create mode 100644 deps/rabbitmq_web_dispatch/src/rabbit_webmachine.erl create mode 100644 deps/rabbitmq_web_dispatch/src/rabbit_webmachine_error_handler.erl create mode 100644 deps/rabbitmq_web_dispatch/src/rabbitmq_web_dispatch.app.src rename {rabbitmq-server/deps/rabbitmq_web_mqtt => deps/rabbitmq_web_stomp}/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt => deps/rabbitmq_web_stomp}/LICENSE (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp}/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/Makefile (68%) create mode 100644 deps/rabbitmq_web_stomp/README.md create mode 100644 deps/rabbitmq_web_stomp/erlang.mk create mode 100644 deps/rabbitmq_web_stomp/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/src/rabbit_ws_app.erl (93%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/src/rabbit_ws_client.erl (92%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/src/rabbit_ws_client_sup.erl (95%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/src/rabbit_ws_handler.erl (100%) create mode 100644 deps/rabbitmq_web_stomp/src/rabbit_ws_sockjs.erl rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp/src/rabbit_ws_sup.erl (94%) create mode 100644 deps/rabbitmq_web_stomp/src/rabbitmq_web_stomp.app.src rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp_examples}/CODE_OF_CONDUCT.md (100%) rename {rabbitmq-server/deps/rabbitmq_web_stomp => deps/rabbitmq_web_stomp_examples}/CONTRIBUTING.md (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/LICENSE (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/LICENSE-APL2-Stomp-Websocket (100%) rename {rabbitmq-server/deps/rabbitmq_web_stomp => deps/rabbitmq_web_stomp_examples}/LICENSE-MPL-RabbitMQ (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/Makefile (64%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/README.md (100%) create mode 100644 deps/rabbitmq_web_stomp_examples/erlang.mk rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/priv/bunny.html (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp_examples}/priv/bunny.png (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/priv/echo.html (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/priv/index.html (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp_examples}/priv/main.css (100%) rename {rabbitmq-server/deps/rabbitmq_web_mqtt_examples => deps/rabbitmq_web_stomp_examples}/priv/pencil.cur (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/priv/stomp.js (100%) rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/priv/temp-queue.html (100%) create mode 100644 deps/rabbitmq_web_stomp_examples/rabbitmq-components.mk rename {rabbitmq-server/deps => deps}/rabbitmq_web_stomp_examples/src/rabbit_web_stomp_examples_app.erl (95%) create mode 100644 deps/rabbitmq_web_stomp_examples/src/rabbitmq_web_stomp_examples.app.src create mode 100644 deps/ranch/AUTHORS rename {rabbitmq-server/deps => deps}/ranch/CHANGELOG.asciidoc (51%) rename {rabbitmq-server/deps => deps}/ranch/LICENSE (92%) rename {rabbitmq-server/deps => deps}/ranch/Makefile (58%) rename {rabbitmq-server/deps => deps}/ranch/README.asciidoc (56%) create mode 100644 deps/ranch/appveyor.yml rename {rabbitmq-server/deps/cowlib => deps/ranch}/circle.yml (75%) create mode 100644 deps/ranch/doc/src/guide/book.asciidoc create mode 100644 deps/ranch/doc/src/guide/embedded.asciidoc create mode 100644 deps/ranch/doc/src/guide/internals.asciidoc create mode 100644 deps/ranch/doc/src/guide/introduction.asciidoc create mode 100644 deps/ranch/doc/src/guide/listeners.asciidoc create mode 100644 deps/ranch/doc/src/guide/parsers.asciidoc create mode 100644 deps/ranch/doc/src/guide/protocols.asciidoc create mode 100644 deps/ranch/doc/src/guide/ssl_auth.asciidoc create mode 100644 deps/ranch/doc/src/guide/transports.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch_app.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch_protocol.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch_ssl.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch_tcp.asciidoc create mode 100644 deps/ranch/doc/src/manual/ranch_transport.asciidoc create mode 100644 deps/ranch/erlang.mk create mode 100644 deps/ranch/examples/tcp_echo/Makefile create mode 100644 deps/ranch/examples/tcp_echo/README.md create mode 100644 deps/ranch/examples/tcp_echo/relx.config create mode 100644 deps/ranch/examples/tcp_echo/src/echo_protocol.erl create mode 100644 deps/ranch/examples/tcp_echo/src/tcp_echo.app.src create mode 100644 deps/ranch/examples/tcp_echo/src/tcp_echo_app.erl create mode 100644 deps/ranch/examples/tcp_echo/src/tcp_echo_sup.erl create mode 100644 deps/ranch/examples/tcp_reverse/Makefile create mode 100644 deps/ranch/examples/tcp_reverse/README.md create mode 100644 deps/ranch/examples/tcp_reverse/relx.config create mode 100644 deps/ranch/examples/tcp_reverse/src/reverse_protocol.erl create mode 100644 deps/ranch/examples/tcp_reverse/src/tcp_reverse.app.src create mode 100644 deps/ranch/examples/tcp_reverse/src/tcp_reverse_app.erl create mode 100644 deps/ranch/examples/tcp_reverse/src/tcp_reverse_sup.erl create mode 100644 deps/ranch/src/ranch.app.src rename {rabbitmq-server/deps => deps}/ranch/src/ranch.erl (62%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_acceptor.erl (92%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_acceptors_sup.erl (70%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_app.erl (95%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_conns_sup.erl (83%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_listener_sup.erl (84%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_protocol.erl (94%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_server.erl (89%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_ssl.erl (88%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_sup.erl (94%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_tcp.erl (91%) rename {rabbitmq-server/deps => deps}/ranch/src/ranch_transport.erl (98%) rename {rabbitmq-server/deps => deps}/sockjs/COPYING (100%) rename {rabbitmq-server/deps => deps}/sockjs/Changelog (100%) rename {rabbitmq-server/deps => deps}/sockjs/LICENSE-APL2-Rebar (100%) rename {rabbitmq-server/deps => deps}/sockjs/LICENSE-EPL-OTP (100%) rename {rabbitmq-server/deps => deps}/sockjs/LICENSE-MIT-Mochiweb (100%) rename {rabbitmq-server/deps => deps}/sockjs/LICENSE-MIT-SockJS (100%) rename {rabbitmq-server/deps => deps}/sockjs/Makefile (85%) rename {rabbitmq-server/deps => deps}/sockjs/Makefile.orig.mk (100%) rename {rabbitmq-server/deps => deps}/sockjs/README.md (100%) create mode 100755 deps/sockjs/examples/cowboy_echo.erl create mode 100755 deps/sockjs/examples/cowboy_echo_authen_callback.erl create mode 100755 deps/sockjs/examples/cowboy_test_server.erl create mode 100644 deps/sockjs/examples/echo.html create mode 100644 deps/sockjs/examples/echo_authen_callback.html create mode 100755 deps/sockjs/examples/multiplex/cowboy_multiplex.erl create mode 100755 deps/sockjs/examples/multiplex/cowboy_multiplex_authen_callback.erl create mode 100644 deps/sockjs/examples/multiplex/index.html create mode 100644 deps/sockjs/examples/multiplex/index_authen_callback.html rename {rabbitmq-server/deps => deps}/sockjs/rebar (100%) rename {rabbitmq-server/deps => deps}/sockjs/rebar.config (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/mochijson2_fork.erl (89%) rename {rabbitmq-server/deps => deps}/sockjs/src/mochinum_fork.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs.app.src (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_action.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_app.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_cowboy_handler.erl (92%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_filters.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_handler.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_http.erl (87%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_internal.hrl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_json.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_multiplex.erl (98%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_multiplex_channel.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_service.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_session.erl (98%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_session_sup.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_util.erl (100%) rename {rabbitmq-server/deps => deps}/sockjs/src/sockjs_ws_handler.erl (100%) create mode 100644 deps/webmachine/Emakefile create mode 100644 deps/webmachine/LICENSE create mode 100644 deps/webmachine/Makefile create mode 100644 deps/webmachine/Makefile.orig.mk create mode 100644 deps/webmachine/README.org create mode 100644 deps/webmachine/THANKS create mode 100644 deps/webmachine/demo/Makefile create mode 100644 deps/webmachine/demo/README create mode 100644 deps/webmachine/demo/priv/dispatch.conf create mode 100644 deps/webmachine/demo/rebar.config create mode 100644 deps/webmachine/demo/src/webmachine_demo.app.src create mode 100644 deps/webmachine/demo/src/webmachine_demo.erl create mode 100644 deps/webmachine/demo/src/webmachine_demo_app.erl create mode 100644 deps/webmachine/demo/src/webmachine_demo_fs_resource.erl create mode 100644 deps/webmachine/demo/src/webmachine_demo_resource.erl create mode 100644 deps/webmachine/demo/src/webmachine_demo_sup.erl create mode 100755 deps/webmachine/demo/start.sh create mode 100644 deps/webmachine/docs/http-headers-status-v3.png create mode 100644 deps/webmachine/include/webmachine.hrl rename {rabbitmq-server/deps/rabbitmq_web_dispatch/src => deps/webmachine/include}/webmachine_logger.hrl (100%) create mode 100644 deps/webmachine/include/wm_reqdata.hrl create mode 100644 deps/webmachine/include/wm_reqstate.hrl create mode 100644 deps/webmachine/include/wm_resource.hrl create mode 100644 deps/webmachine/priv/templates/Makefile create mode 100644 deps/webmachine/priv/templates/README create mode 100644 deps/webmachine/priv/templates/priv/dispatch.conf create mode 100644 deps/webmachine/priv/templates/rebar.config create mode 100644 deps/webmachine/priv/templates/src/wmskel.app.src create mode 100644 deps/webmachine/priv/templates/src/wmskel.erl create mode 100644 deps/webmachine/priv/templates/src/wmskel_app.erl create mode 100644 deps/webmachine/priv/templates/src/wmskel_resource.erl create mode 100644 deps/webmachine/priv/templates/src/wmskel_sup.erl create mode 100644 deps/webmachine/priv/templates/start.sh create mode 100644 deps/webmachine/priv/templates/wmskel.template create mode 100644 deps/webmachine/priv/trace/http-headers-status-v3.png create mode 100755 deps/webmachine/priv/trace/wmtrace.css create mode 100755 deps/webmachine/priv/trace/wmtrace.js create mode 100644 deps/webmachine/priv/www/index.html create mode 100755 deps/webmachine/rebar create mode 100644 deps/webmachine/rebar.config create mode 100644 deps/webmachine/rebar.config.script create mode 100755 deps/webmachine/scripts/new_webmachine.sh create mode 100644 deps/webmachine/src/webmachine.app.src create mode 100644 deps/webmachine/src/webmachine.erl create mode 100644 deps/webmachine/src/webmachine_app.erl create mode 100644 deps/webmachine/src/webmachine_decision_core.erl create mode 100644 deps/webmachine/src/webmachine_deps.erl create mode 100644 deps/webmachine/src/webmachine_dispatcher.erl create mode 100644 deps/webmachine/src/webmachine_error.erl create mode 100644 deps/webmachine/src/webmachine_error_handler.erl rename {rabbitmq-server/deps/rabbitmq_web_dispatch => deps/webmachine}/src/webmachine_log.erl (98%) rename {rabbitmq-server/deps/rabbitmq_web_dispatch => deps/webmachine}/src/webmachine_log_handler.erl (73%) create mode 100644 deps/webmachine/src/webmachine_logger_watcher.erl create mode 100644 deps/webmachine/src/webmachine_logger_watcher_sup.erl create mode 100644 deps/webmachine/src/webmachine_mochiweb.erl create mode 100644 deps/webmachine/src/webmachine_multipart.erl create mode 100644 deps/webmachine/src/webmachine_perf_log_handler.erl create mode 100644 deps/webmachine/src/webmachine_request.erl create mode 100644 deps/webmachine/src/webmachine_resource.erl create mode 100644 deps/webmachine/src/webmachine_router.erl create mode 100644 deps/webmachine/src/webmachine_sup.erl create mode 100644 deps/webmachine/src/webmachine_util.erl create mode 100755 deps/webmachine/src/wmtrace_resource.erl create mode 100644 deps/webmachine/src/wrq.erl create mode 100755 deps/webmachine/start-dev.sh create mode 100755 deps/webmachine/start.sh create mode 100644 deps/webmachine/www/blogs.html create mode 100644 deps/webmachine/www/contact.html create mode 100644 deps/webmachine/www/css/style-1c.css create mode 100755 deps/webmachine/www/css/style.css create mode 100644 deps/webmachine/www/debugging.html create mode 100644 deps/webmachine/www/diagram.html create mode 100644 deps/webmachine/www/dispatcher.html create mode 100644 deps/webmachine/www/docs.html create mode 100644 deps/webmachine/www/example_resources.html create mode 100644 deps/webmachine/www/favicon.ico create mode 100644 deps/webmachine/www/images/WM200-crop.png create mode 100644 deps/webmachine/www/images/basho-landscape.gif create mode 100644 deps/webmachine/www/images/basic-trace-decision-tab.png create mode 100644 deps/webmachine/www/images/basic-trace-labeled.png create mode 100644 deps/webmachine/www/images/basic-trace-request-tab.png create mode 100644 deps/webmachine/www/images/basic-trace-response-tab.png create mode 100755 deps/webmachine/www/images/bg.gif create mode 100644 deps/webmachine/www/images/blankbox.gif create mode 100644 deps/webmachine/www/images/chash.gif create mode 100644 deps/webmachine/www/images/easy-ops.gif create mode 100644 deps/webmachine/www/images/gossip4.gif create mode 100644 deps/webmachine/www/images/halfblankbox.gif create mode 100644 deps/webmachine/www/images/http-headers-status-v3.png create mode 100644 deps/webmachine/www/images/more.gif create mode 100755 deps/webmachine/www/images/site.gif create mode 100644 deps/webmachine/www/images/splash250.gif create mode 100644 deps/webmachine/www/images/vclock.gif create mode 100755 deps/webmachine/www/index.html create mode 100644 deps/webmachine/www/intros.html create mode 100644 deps/webmachine/www/mechanics.html create mode 100644 deps/webmachine/www/quickstart.html create mode 100644 deps/webmachine/www/reftrans.html create mode 100644 deps/webmachine/www/reqdata.html create mode 100644 deps/webmachine/www/resources.html create mode 100644 deps/webmachine/www/streambody.html create mode 100644 erlang.mk create mode 100644 git-revisions.txt create mode 100644 rabbitmq-components.mk delete mode 100644 rabbitmq-server/README.md delete mode 100644 rabbitmq-server/deps/amqp_client/erlang.mk delete mode 100644 rabbitmq-server/deps/cowboy/erlang.mk delete mode 100644 rabbitmq-server/deps/cowlib/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbit/CONTRIBUTING.md delete mode 100644 rabbitmq-server/deps/rabbit/Makefile delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_control_pbe.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_core_metrics_gc.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_credential_validation.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_credential_validator.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_credential_validator_accept_everything.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_credential_validator_min_password_length.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_credential_validator_password_regexp.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_fhc_helpers.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_metrics.erl delete mode 100644 rabbitmq-server/deps/rabbit/src/rabbit_ssl.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/Makefile delete mode 100644 rabbitmq-server/deps/rabbit_common/development.pre.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/include/rabbit_core_metrics.hrl delete mode 100644 rabbitmq-server/deps/rabbit_common/include/rabbit_memory.hrl delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-build.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-components.hexpm.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-early-plugin.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-early-test.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-hexpm.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/mk/rabbitmq-test.mk delete mode 100644 rabbitmq-server/deps/rabbit_common/src/ets_compat.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_amqqueue_common.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_basic_common.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_channel_common.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_core_metrics.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_data_coercion.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_nodes_common.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_queue_collector_common.erl delete mode 100644 rabbitmq-server/deps/rabbit_common/src/rabbit_ssl_options.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_backend_ldap/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_backend_ldap/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_backend_ldap/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_event_exchange/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_event_exchange/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_federation/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_federation/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_federation/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_federation_management/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_federation_management/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_federation_management/src/rabbit_federation_mgmt.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_jms_topic_exchange/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_jms_topic_exchange/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_management/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_management/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_app.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_cors.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_db.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_db_cache.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_db_cache_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_stats.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_sup_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_global_parameter.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_global_parameters.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_redirect.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_reset.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_static.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_user.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/include/rabbit_mgmt_metrics.hrl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/exometer_slide.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_config.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_data.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_gc.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_metrics_collector.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_metrics_gc.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_storage.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_management_visualiser/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/js/visualiser.js delete mode 100644 rabbitmq-server/deps/rabbitmq_management_visualiser/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_mqtt/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_mqtt/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_mqtt/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_noop.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_recent_history_exchange/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_recent_history_exchange/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_sharding/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_sharding/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_shovel/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_shovel/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_shovel/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_shovel_management/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_shovel_management/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_stomp/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_stomp/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_stomp/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_top/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_top/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_tracing/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_tracing/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_tracing/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbit_trust_store_opera_com_provider.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/README.md delete mode 100755 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/manage.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/__init__.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/settings.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/trust_store/__init__.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/trust_store/apps.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/trust_store/tests.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/trust_store/urls.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/trust_store/views.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/urls.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/examples/rabbitmq_trust_store_django/rabbitmq_trust_store_django/wsgi.py delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_certificate_provider.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_file_provider.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_http_provider.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_cowboy_middleware.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_cowboy_redirect.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_listing_handler.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/LICENSE-MPL-RabbitMQ delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/src/rabbit_web_mqtt_app.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/src/rabbit_web_mqtt_connection_sup.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/src/rabbit_web_mqtt_handler.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt/src/rabbit_web_mqtt_middleware.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/LICENSE delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/Makefile delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/priv/bunny.html delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/priv/echo.html delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/priv/index.html delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/priv/mqttws31.js delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_mqtt_examples/src/rabbit_web_mqtt_examples_app.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/CODE_OF_CONDUCT.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/LICENSE delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/README.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/rabbitmq-components.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp/src/rabbit_ws_sockjs.erl delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/CODE_OF_CONDUCT.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/CONTRIBUTING.md delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/LICENSE-MPL-RabbitMQ delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/erlang.mk delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/priv/bunny.png delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/priv/main.css delete mode 100755 rabbitmq-server/deps/rabbitmq_web_stomp_examples/priv/pencil.cur delete mode 100644 rabbitmq-server/deps/rabbitmq_web_stomp_examples/rabbitmq-components.mk delete mode 100644 rabbitmq-server/erlang.mk delete mode 100644 rabbitmq-server/git-revisions.txt delete mode 100644 rabbitmq-server/plugins.mk delete mode 100644 rabbitmq-server/rabbitmq-components.mk rename {rabbitmq-server/scripts => scripts}/rabbitmq-script-wrapper (83%) rename {rabbitmq-server/scripts => scripts}/rabbitmq-server-ha.ocf (98%) rename {rabbitmq-server/scripts => scripts}/rabbitmq-server.ocf (92%) create mode 100644 scripts/travis_test_ocf_ra.sh create mode 100644 upgrade/Makefile create mode 100644 upgrade/README.md create mode 100644 upgrade/config/enabled_plugins create mode 100644 upgrade/config/rabbitmq.config create mode 100644 upgrade/scripts/upgrade-from-3.5-helpers.sh create mode 100755 upgrade/scripts/upgrade-from.sh create mode 100644 upgrade/scripts/upgrade-helpers.sh create mode 100644 upgrade/scripts/upgrade-to-3.6-helpers.sh create mode 100644 upgrade/scripts/upgrade-to-3.7-helpers.sh create mode 100755 upgrade/scripts/upgrade-to.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..845ca06 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pc diff --git a/rabbitmq-server/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/CODE_OF_CONDUCT.md rename to CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/CONTRIBUTING.md rename to CONTRIBUTING.md diff --git a/rabbitmq-server/LICENSE b/LICENSE similarity index 100% rename from rabbitmq-server/LICENSE rename to LICENSE diff --git a/rabbitmq-server/LICENSE-APACHE2-ExplorerCanvas b/LICENSE-APACHE2-ExplorerCanvas similarity index 100% rename from rabbitmq-server/LICENSE-APACHE2-ExplorerCanvas rename to LICENSE-APACHE2-ExplorerCanvas diff --git a/rabbitmq-server/LICENSE-APL2-Rebar b/LICENSE-APL2-Rebar similarity index 100% rename from rabbitmq-server/LICENSE-APL2-Rebar rename to LICENSE-APL2-Rebar diff --git a/rabbitmq-server/LICENSE-APL2-Stomp-Websocket b/LICENSE-APL2-Stomp-Websocket similarity index 100% rename from rabbitmq-server/LICENSE-APL2-Stomp-Websocket rename to LICENSE-APL2-Stomp-Websocket diff --git a/rabbitmq-server/LICENSE-BSD-base64js b/LICENSE-BSD-base64js similarity index 100% rename from rabbitmq-server/LICENSE-BSD-base64js rename to LICENSE-BSD-base64js diff --git a/rabbitmq-server/LICENSE-BSD-glMatrix b/LICENSE-BSD-glMatrix similarity index 100% rename from rabbitmq-server/LICENSE-BSD-glMatrix rename to LICENSE-BSD-glMatrix diff --git a/rabbitmq-server/LICENSE-EPL-OTP b/LICENSE-EPL-OTP similarity index 100% rename from rabbitmq-server/LICENSE-EPL-OTP rename to LICENSE-EPL-OTP diff --git a/rabbitmq-server/LICENSE-MIT-EJS10 b/LICENSE-MIT-EJS10 similarity index 100% rename from rabbitmq-server/LICENSE-MIT-EJS10 rename to LICENSE-MIT-EJS10 diff --git a/rabbitmq-server/LICENSE-MIT-Erlware-Commons b/LICENSE-MIT-Erlware-Commons similarity index 100% rename from rabbitmq-server/LICENSE-MIT-Erlware-Commons rename to LICENSE-MIT-Erlware-Commons diff --git a/rabbitmq-server/LICENSE-MIT-Flot b/LICENSE-MIT-Flot similarity index 100% rename from rabbitmq-server/LICENSE-MIT-Flot rename to LICENSE-MIT-Flot diff --git a/rabbitmq-server/LICENSE-MIT-Mochi b/LICENSE-MIT-Mochi similarity index 100% rename from rabbitmq-server/LICENSE-MIT-Mochi rename to LICENSE-MIT-Mochi diff --git a/rabbitmq-server/LICENSE-MIT-Mochiweb b/LICENSE-MIT-Mochiweb similarity index 100% rename from rabbitmq-server/LICENSE-MIT-Mochiweb rename to LICENSE-MIT-Mochiweb diff --git a/rabbitmq-server/LICENSE-MIT-Sammy060 b/LICENSE-MIT-Sammy060 similarity index 100% rename from rabbitmq-server/LICENSE-MIT-Sammy060 rename to LICENSE-MIT-Sammy060 diff --git a/rabbitmq-server/LICENSE-MIT-SockJS b/LICENSE-MIT-SockJS similarity index 100% rename from rabbitmq-server/LICENSE-MIT-SockJS rename to LICENSE-MIT-SockJS diff --git a/rabbitmq-server/LICENSE-MIT-jQuery164 b/LICENSE-MIT-jQuery164 similarity index 100% rename from rabbitmq-server/LICENSE-MIT-jQuery164 rename to LICENSE-MIT-jQuery164 diff --git a/rabbitmq-server/LICENSE-MPL-RabbitMQ b/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/LICENSE-MPL-RabbitMQ rename to LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/LICENSE-MPL2 b/LICENSE-MPL2 similarity index 100% rename from rabbitmq-server/LICENSE-MPL2 rename to LICENSE-MPL2 diff --git a/rabbitmq-server/Makefile b/Makefile similarity index 82% rename from rabbitmq-server/Makefile rename to Makefile index b625864..5558f48 100644 --- a/rabbitmq-server/Makefile +++ b/Makefile @@ -1,22 +1,38 @@ PROJECT = rabbitmq_server_release -PROJECT_DESCRIPTION = RabbitMQ Server - -# Propagate PROJECT_VERSION (from the command line or environment) to -# other components. If PROJECT_VERSION is unset, then an empty variable -# is propagated and the default version will fallback to the default -# value from rabbitmq-components.mk. -export RABBITMQ_VERSION = $(PROJECT_VERSION) +VERSION ?= 0.0.0 # Release artifacts are put in $(PACKAGES_DIR). PACKAGES_DIR ?= $(abspath PACKAGES) -# List of plugins to include in a RabbitMQ release. -include plugins.mk - DEPS = rabbit_common rabbit $(PLUGINS) -DEP_PLUGINS = rabbit_common/mk/rabbitmq-dist.mk \ - rabbit_common/mk/rabbitmq-run.mk \ +# List of plugins to include in a RabbitMQ release. +PLUGINS := rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_jms_topic_exchange \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_visualiser \ + rabbitmq_mqtt \ + rabbitmq_recent_history_exchange \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-run.mk \ + rabbit_common/mk/rabbitmq-dist.mk \ rabbit_common/mk/rabbitmq-tools.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be @@ -36,7 +52,7 @@ include erlang.mk SOURCE_DIST_BASE ?= rabbitmq-server SOURCE_DIST_SUFFIXES ?= tar.xz zip -SOURCE_DIST ?= $(PACKAGES_DIR)/$(SOURCE_DIST_BASE)-$(PROJECT_VERSION) +SOURCE_DIST ?= $(PACKAGES_DIR)/$(SOURCE_DIST_BASE)-$(VERSION) # The first source distribution file is used by packages: if the archive # type changes, you must update all packages' Makefile. @@ -62,36 +78,27 @@ RSYNC_FLAGS += -a $(RSYNC_V) \ --exclude '.travis.yml' \ --exclude '.*.plt' \ --exclude '$(notdir $(ERLANG_MK_TMP))' \ - --exclude '_build/' \ + --exclude 'ebin' \ + --exclude 'packaging' \ + --exclude 'erl_crash.dump' \ + --exclude 'MnesiaCore.*' \ --exclude 'cover/' \ --exclude 'deps/' \ --exclude 'ebin/' \ - --exclude 'erl_crash.dump' \ - --exclude 'MnesiaCore.*' \ --exclude '$(notdir $(DEPS_DIR))/' \ - --exclude 'hexer*' \ --exclude 'logs/' \ - --exclude 'packaging' \ --exclude 'plugins/' \ --exclude '$(notdir $(DIST_DIR))/' \ --exclude 'test' \ --exclude 'xrefr' \ --exclude '/$(notdir $(PACKAGES_DIR))/' \ --exclude '/PACKAGES/' \ - --exclude '/upgrade/' \ - --exclude '/amqp_client/doc/' \ - --exclude '/amqp_client/rebar.config' \ --exclude '/cowboy/doc/' \ --exclude '/cowboy/examples/' \ - --exclude '/rabbit/escript/' \ --exclude '/rabbitmq_amqp1_0/test/swiftmq/build/'\ --exclude '/rabbitmq_amqp1_0/test/swiftmq/swiftmq*'\ - --exclude '/rabbitmq_cli/escript/' \ --exclude '/rabbitmq_mqtt/test/build/' \ --exclude '/rabbitmq_mqtt/test/test_client/'\ - --exclude '/ranch/doc/' \ - --exclude '/ranch/examples/' \ - --exclude '/sockjs/examples/' \ --delete \ --delete-excluded @@ -117,8 +124,7 @@ ZIP_V = $(ZIP_V_$(V)) $(SOURCE_DIST): $(ERLANG_MK_RECURSIVE_DEPS_LIST) $(verbose) mkdir -p $(dir $@) $(gen_verbose) $(RSYNC) $(RSYNC_FLAGS) ./ $@/ - $(verbose) echo "$(PROJECT_DESCRIPTION) $(PROJECT_VERSION)" > $@/git-revisions.txt - $(verbose) echo "$(PROJECT) $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)" >> $@/git-revisions.txt + $(verbose) echo "$(PROJECT) $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)" > $@/git-revisions.txt $(verbose) cat packaging/common/LICENSE.head > $@/LICENSE $(verbose) mkdir -p $@/deps/licensing $(verbose) for dep in $$(cat $(ERLANG_MK_RECURSIVE_DEPS_LIST) | LC_COLLATE=C sort); do \ @@ -143,47 +149,49 @@ $(SOURCE_DIST): $(ERLANG_MK_RECURSIVE_DEPS_LIST) $(verbose) cat packaging/common/LICENSE.tail >> $@/LICENSE $(verbose) find $@/deps/licensing -name 'LICENSE-*' -exec cp '{}' $@ \; $(verbose) for file in $$(find $@ -name '*.app.src'); do \ - sed -E -i.bak \ - -e 's/[{]vsn[[:blank:]]*,[[:blank:]]*(""|"0.0.0")[[:blank:]]*}/{vsn, "$(PROJECT_VERSION)"}/' \ - -e 's/[{]broker_version_requirements[[:blank:]]*,[[:blank:]]*\[\][[:blank:]]*}/{broker_version_requirements, ["$(PROJECT_VERSION)"]}/' \ - $$file; \ + sed -E -i.bak -e 's/[{]vsn[[:blank:]]*,[[:blank:]]*(""|"0.0.0")[[:blank:]]*}/{vsn, "$(VERSION)"}/' $$file; \ rm $$file.bak; \ done - $(verbose) echo "PLUGINS := $(PLUGINS)" > $@/plugins.mk - -$(SOURCE_DIST).manifest: $(SOURCE_DIST) - $(gen_verbose) cd $(dir $(SOURCE_DIST)) && \ - find $(notdir $(SOURCE_DIST)) | LC_COLLATE=C sort > $@ # TODO: Fix file timestamps to have reproducible source archives. # $(verbose) find $@ -not -name 'git-revisions.txt' -print0 | xargs -0 touch -r $@/git-revisions.txt -$(SOURCE_DIST).tar.gz: $(SOURCE_DIST).manifest +$(SOURCE_DIST).tar.gz: $(SOURCE_DIST) $(gen_verbose) cd $(dir $(SOURCE_DIST)) && \ - $(TAR) $(TAR_V) -T $(SOURCE_DIST).manifest --no-recursion -cf - | \ + find $(notdir $(SOURCE_DIST)) -print0 | LC_COLLATE=C sort -z | \ + xargs -0 $(TAR) $(TAR_V) --no-recursion -cf - | \ $(GZIP) --best > $@ -$(SOURCE_DIST).tar.bz2: $(SOURCE_DIST).manifest +$(SOURCE_DIST).tar.bz2: $(SOURCE_DIST) $(gen_verbose) cd $(dir $(SOURCE_DIST)) && \ - $(TAR) $(TAR_V) -T $(SOURCE_DIST).manifest --no-recursion -cf - | \ + find $(notdir $(SOURCE_DIST)) -print0 | LC_COLLATE=C sort -z | \ + xargs -0 $(TAR) $(TAR_V) --no-recursion -cf - | \ $(BZIP2) > $@ -$(SOURCE_DIST).tar.xz: $(SOURCE_DIST).manifest +$(SOURCE_DIST).tar.xz: $(SOURCE_DIST) $(gen_verbose) cd $(dir $(SOURCE_DIST)) && \ - $(TAR) $(TAR_V) -T $(SOURCE_DIST).manifest --no-recursion -cf - | \ + find $(notdir $(SOURCE_DIST)) -print0 | LC_COLLATE=C sort -z | \ + xargs -0 $(TAR) $(TAR_V) --no-recursion -cf - | \ $(XZ) > $@ -$(SOURCE_DIST).zip: $(SOURCE_DIST).manifest +$(SOURCE_DIST).zip: $(SOURCE_DIST) $(verbose) rm -f $@ $(gen_verbose) cd $(dir $(SOURCE_DIST)) && \ - $(ZIP) $(ZIP_V) --names-stdin $@ < $(SOURCE_DIST).manifest + find $(notdir $(SOURCE_DIST)) -print0 | LC_COLLATE=C sort -z | \ + xargs -0 $(ZIP) $(ZIP_V) $@ -clean:: clean-source-dist +clean:: clean-source-dist clean-upgrade + +clean-upgrade: + cd upgrade && make clean clean-source-dist: $(gen_verbose) rm -rf -- $(SOURCE_DIST_BASE)-* -distclean:: distclean-packages +distclean:: distclean-packages distclean-upgrade + +distclean-upgrade: + cd upgrade && make distclean distclean-packages: $(gen_verbose) rm -rf -- $(PACKAGES_DIR) @@ -202,8 +210,6 @@ clean-unpacked-source-dist: .PHONY: packages package-deb \ package-rpm package-rpm-fedora package-rpm-suse \ package-windows package-standalone-macosx \ - package-standalone-linux-x86_64 \ - package-standalone-freebsd-x86_64 \ package-generic-unix # This variable is exported so sub-make instances know where to find the @@ -212,8 +218,6 @@ PACKAGES_SOURCE_DIST_FILE ?= $(firstword $(SOURCE_DIST_FILES)) packages package-deb package-rpm package-rpm-fedora \ package-rpm-suse package-windows package-standalone-macosx \ -package-standalone-linux-x86_64 \ -package-standalone-freebsd-x86_64 \ package-generic-unix: $(PACKAGES_SOURCE_DIST_FILE) $(verbose) $(MAKE) -C packaging $@ \ SOURCE_DIST_FILE=$(abspath $(PACKAGES_SOURCE_DIST_FILE)) @@ -234,13 +238,13 @@ manpages web-manpages distclean-manpages: DESTDIR ?= PREFIX ?= /usr/local -WINDOWS_PREFIX ?= rabbitmq-server-windows-$(PROJECT_VERSION) +WINDOWS_PREFIX ?= rabbitmq-server-windows-$(VERSION) MANDIR ?= $(PREFIX)/share/man RMQ_ROOTDIR ?= $(PREFIX)/lib/erlang RMQ_BINDIR ?= $(RMQ_ROOTDIR)/bin RMQ_LIBDIR ?= $(RMQ_ROOTDIR)/lib -RMQ_ERLAPP_DIR ?= $(RMQ_LIBDIR)/rabbitmq_server-$(PROJECT_VERSION) +RMQ_ERLAPP_DIR ?= $(RMQ_LIBDIR)/rabbitmq_server-$(VERSION) SCRIPTS = rabbitmq-defaults \ rabbitmq-env \ @@ -367,3 +371,6 @@ install-windows-docs: install-windows-erlapp *) mv "$$file" "$$file.txt" ;; \ esac; \ done + +test-upgrade: + $(MAKE) -C upgrade diff --git a/debian/changelog b/debian/changelog index 1f18ffc..19742a6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,555 +1,451 @@ -rabbitmq-server (3.6.11-1~u14.04+mcp1) mcp; urgency=medium +rabbitmq-server (3.6.6-1~u14.04+mcp1) mcp; urgency=medium - * Update sources. + * Rebuild for trusty-mitaka mcp branch - -- Ivan Udovichenko Wed, 27 Dec 2017 17:28:16 +0300 + -- Ivan Udovichenko Thu, 09 Mar 2017 15:55:29 +0200 -rabbitmq-server (3.6.10-1) unstable; urgency=medium +rabbitmq-server (3.6.6-1~u14.04+mos2) mos9.0; urgency=medium - * New upstream release (Closes: #863586), fixing multiple issues: - - CVE-2017-4965: XSS vulnerabilities in management UI - - CVE-2017-4966: authentication details are stored in browser-local storage - without expiration - - CVE-2017-4967: XSS vulnerabilities in management UI + * Use HiPE-compilation - -- Thomas Goirand Wed, 28 Jun 2017 15:00:41 +0200 + -- Alexey Lebedeff Fri, 11 Nov 2016 15:06:56 +0000 -rabbitmq-server (3.6.6-1) unstable; urgency=medium +rabbitmq-server (3.6.6-1~u14.04+mos1) mos9.0; urgency=medium - [ Ondřej Nový ] - * Team upload. - * New upstream release (Closes: #849849, CVE-2016-9877) - * d/copyright: Fixed for new release - * d/ocf: Removed, use upstream one + * new upstream release - -- Ondřej Kobližek Mon, 02 Jan 2017 15:49:03 +0100 + -- Alexey Lebedeff Fri, 11 Nov 2016 15:06:56 +0000 -rabbitmq-server (3.6.5-1) unstable; urgency=medium +rabbitmq-server (3.6.5.907-1) unstable; urgency=low - [ James Page ] - * New upstream release (Closes: #812377): - - Builds fine with the new erlang (Closes: #837241). - * [fa2d29e] Update watch file for upstream xz compression. (Closes: #813628). - * [b008e08] Imported Upstream version 3.6.0. - * [d0dc477] Update gbp configuration for dch use. - - [ Thomas Goirand ] - * Also packaging the rabbitmqadmin cli. - * Do not do dh_auto_clean, as it removes all the deps folder. - * Disabled tests, as they download from github. - * Replaced git-core transition package by git in build-depends. - * Added rsync as build-depends-indep. - * Fix DESTDIR=$(DEB_DESTDIR) PREFIX=/usr as upstream Makefile changed. - * Added python-all and dh-python as build-depends. - * Update of debian/copyright for the new deps/* path from upstream, updated - debian/* info and fixed order. - * Copy some stuff from the upstream pacakging in debian/rules. - * Runtime depends on lsb-base. - * Overrides lintian false positive error js source missing. + * New Upstream Release - [ Ondřej Nový ] - * Fixed VCS URLs (https). - * Fixed python shebang. - * Standards-Version is 3.9.8 now (no change). + -- Michael Klishin Mon, 21 Nov 2016 10:36:28 +0000 - -- Thomas Goirand Sun, 14 Feb 2016 13:35:22 +0800 +rabbitmq-server (3.6.5-1) unstable; urgency=low -rabbitmq-server (3.5.7-1) unstable; urgency=medium + * New Upstream Release - * New upstream release. + -- Michael Klishin Fri, 05 Aug 2016 14:20:47 +0100 - -- James Page Mon, 18 Jan 2016 14:05:40 +0000 +rabbitmq-server (3.6.4-1) unstable; urgency=low -rabbitmq-server (3.5.4-3.1) unstable; urgency=medium + * New Upstream Release - * Non-maintainer upload. - * Make the default configuration file, which is read unconditionally on - startup, readable by others. This makes it possible to run rabbitmq-server - as users other than rabbitmq, e.g. when running test suites as part of - package builds (Closes: #801917) + -- Michael Klishin Fri, 29 Jul 2016 11:40:53 +0100 - -- Antonio Terceiro Sat, 31 Oct 2015 12:56:15 -0200 +rabbitmq-server (3.6.3-1) unstable; urgency=low -rabbitmq-server (3.5.4-3) unstable; urgency=medium + * New Upstream Release - * Fix /etc/rabbitmq creation (adding -p to mkdir for upgrades). Thanks to - Frederic Peters for the bug report (Closes: #801088). + -- Michael Klishin Wed, 06 Jul 2016 19:19:21 +0100 - -- Thomas Goirand Tue, 06 Oct 2015 14:07:39 +0000 +rabbitmq-server (3.6.2-1) unstable; urgency=low -rabbitmq-server (3.5.4-2) unstable; urgency=medium + * New Upstream Release - * Cosmetic clean-up in debian/rabbitmq-server.postinst and .init. - * Fix the user / group of /etc/rabbitmq folder and conf files. - * Also fix user / group of an eventual /etc/rabbitmq/enabled_plugins when - upgrading the package. + -- Michael Klishin Thu, 19 May 2016 09:20:06 +0100 - -- Thomas Goirand Mon, 05 Oct 2015 15:47:58 +0200 +rabbitmq-server (3.6.1-1) unstable; urgency=low -rabbitmq-server (3.5.4-1) unstable; urgency=medium + * New Upstream Release - * New upstream release. + -- Michael Klishin Tue, 01 Mar 2016 13:19:57 +0000 - -- James Page Tue, 04 Aug 2015 14:52:31 +0200 +rabbitmq-server (3.6.0-1) unstable; urgency=low -rabbitmq-server (3.5.1-2) unstable; urgency=medium + * New Upstream Release - [ Tony Breeds ] - * systemd: Ensure that rabbitmq has started before marking service as - running (LP: #1449056). + -- Michael Klishin Tue, 22 Dec 2015 13:21:56 +0000 - [ James Page ] - * systemd: Drop use of /etc/default/rabbitmq-server. +rabbitmq-server (3.5.7-1) unstable; urgency=low - -- James Page Tue, 02 Jun 2015 11:40:59 +0100 + * New Upstream Release -rabbitmq-server (3.5.1-1) unstable; urgency=medium + -- Michael Klishin Tue, 15 Dec 2015 10:10:46 +0000 - * New upstream release. +rabbitmq-server (3.5.6-1) unstable; urgency=low - -- James Page Wed, 13 May 2015 21:35:52 +0100 + * New Upstream Release -rabbitmq-server (3.4.3-2) unstable; urgency=medium + -- Michael Klishin Wed, 07 Oct 2015 13:31:24 +0100 - * Restore missing changes from 3.4.2-4. +rabbitmq-server (3.5.5-3) unstable; urgency=low - -- James Page Mon, 02 Feb 2015 07:44:33 +0200 + * Fix bashism in rabbitmq-script-wrapper -rabbitmq-server (3.4.3-1) unstable; urgency=medium + -- Jean-Sébastien Pédron Thu, 24 Sep 2015 19:18:17 +0100 - * New upstream point release. +rabbitmq-server (3.5.5-1) unstable; urgency=low - -- James Page Wed, 28 Jan 2015 16:12:32 +0000 + * New Upstream Release -rabbitmq-server (3.4.2-4) unstable; urgency=medium + -- Jean-Sébastien Pédron Thu, 24 Sep 2015 10:57:25 +0100 - * Re-added /usr/lib/erlang/lib /var/lib/rabbitmq/mnesia and - /var/log/rabbitmq which I removed form the package by mistake on the last - upload. +rabbitmq-server (3.5.4-1) unstable; urgency=low - -- Thomas Goirand Wed, 28 Jan 2015 13:11:02 +0000 + * New Upstream Release -rabbitmq-server (3.4.2-3) unstable; urgency=medium + -- Michael Klishin Tue, 21 Jul 2015 20:25:48 +0100 - * Removes debian/README which is useless (Closes: #703021). - * Provides a default /etc/rabbitmq/rabbitmq-env.conf (Closes: #543638). +rabbitmq-server (3.5.3-1) unstable; urgency=low - -- Thomas Goirand Tue, 27 Jan 2015 15:08:08 +0100 + * New Upstream Release -rabbitmq-server (3.4.2-2) unstable; urgency=medium + -- Jean-Sébastien Pédron Fri, 22 May 2015 11:04:17 +0100 - * d/rabbitmq-server.dirs: Restore missing /etc/rabbitmq directory - (LP: #1410155). +rabbitmq-server (3.5.2-1) unstable; urgency=low - -- James Page Tue, 13 Jan 2015 09:53:47 +0000 + * New Upstream Release -rabbitmq-server (3.4.2-1) unstable; urgency=medium + -- Jean-Sébastien Pédron Tue, 12 May 2015 16:21:44 +0100 - [ James Page ] - * New upstream point release. - * d/control: Update for new maintainer information, add VCS repository - locations. - * d/source/format: Switch packaging to source format 3.0 (quilt). - * d/compat,control: Bump debhelper compat level to 9. - * d/*: wrap-and-sort. - * d/*: Move to standard debhelper, drop use of cdbs. - * d/rules,control,rabbitmq-server.service: Add systemd service - configuration. - * d/control: Bumped Standards-Version 3.9.6, no changes. +rabbitmq-server (3.5.1-1) unstable; urgency=low - [ Thomas Goirand ] - * d/copyright: Rewrote as format 1.0. + * New Upstream Release - -- James Page Fri, 19 Dec 2014 11:09:20 +0000 + -- Michael Klishin Thu, 02 Apr 2015 10:17:30 +0100 -rabbitmq-server (3.4.1-1) unstable; urgency=high +rabbitmq-server (3.5.0-1) unstable; urgency=low - * New upstream release. + * New Upstream Release - -- Blair Hester Tue, 04 Nov 2014 07:33:44 +0100 + -- Jean-Sébastien Pédron Wed, 11 Mar 2015 13:56:19 +0000 -rabbitmq-server (3.3.5-1) unstable; urgency=low +rabbitmq-server (3.4.4-1) unstable; urgency=low - * New upstream release: - - Provides unminimized versions of all bundled Javascript - libraries (Closes: #736781). - * d/control: Added Blair Hester to Uploaders, dropped Emile Joubert - (thanks for all your work Emile!). + * New Upstream Release - -- Blair Hester Tue, 12 Aug 2014 11:47:14 +0100 + -- Michael Klishin Wed, 11 Feb 2015 12:05:01 +0000 -rabbitmq-server (3.3.4-1) unstable; urgency=low +rabbitmq-server (3.4.3-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 24 Jun 2014 18:00:48 +0100 + -- Jean-Sébastien Pédron Tue, 06 Jan 2015 15:58:45 +0000 -rabbitmq-server (3.3.3-1) unstable; urgency=low +rabbitmq-server (3.4.2-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 17 Jun 2014 16:59:14 +0100 + -- Simon MacMullen Wed, 26 Nov 2014 12:11:12 +0000 -rabbitmq-server (3.3.1-1) unstable; urgency=low +rabbitmq-server (3.4.1-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 29 Apr 2014 21:05:49 +0100 + -- Simon MacMullen Wed, 29 Oct 2014 13:31:10 +0000 -rabbitmq-server (3.3.0-1) unstable; urgency=low +rabbitmq-server (3.4.0-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 02 Apr 2014 16:23:08 +0100 + -- Simon MacMullen Tue, 21 Oct 2014 14:21:36 +0100 -rabbitmq-server (3.2.4-1.1) unstable; urgency=high +rabbitmq-server (3.3.5-1) unstable; urgency=low - * Non-maintainer upload. - * Bind on 127.0.0.1 by default, to avoid listening on all ipv6 interface with - guest/guest as default configured user. Note that this only fixes *new* - installation, and that any already existing setup will have to edit the - /etc/rabbitmq/rabbitmq-env.conf manually if affected. (Closes: #727607) - * Removed useless and deprecated DM-Upload field. - * Cleans plugins-src/rabbitmq-server to be able to build twice. Also cleans - debian/postrm which is generated from debian/postrm.in and plugins/README. + * New Upstream Release + * Changed Uploaders from Emile Joubert to Blair Hester - -- Thomas Goirand Mon, 31 Mar 2014 06:11:46 +0000 + -- Simon MacMullen Mon, 11 Aug 2014 12:23:31 +0100 -rabbitmq-server (3.2.4-1) unstable; urgency=low +rabbitmq-server (3.3.4-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 04 Mar 2014 13:21:45 +0000 + -- Simon MacMullen Tue, 24 Jun 2014 12:50:29 +0100 -rabbitmq-server (3.2.3-1) unstable; urgency=low +rabbitmq-server (3.3.3-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 23 Jan 2014 16:49:45 +0000 + -- Simon MacMullen Mon, 16 Jun 2014 13:00:00 +0100 -rabbitmq-server (3.2.2-1) unstable; urgency=low +rabbitmq-server (3.3.2-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 11 Dec 2013 17:31:14 +0000 + -- Simon MacMullen Mon, 09 Jun 2014 10:25:22 +0100 -rabbitmq-server (3.2.1-1) unstable; urgency=low +rabbitmq-server (3.3.1-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Mon, 11 Nov 2013 09:49:42 +0000 + -- Simon MacMullen Tue, 29 Apr 2014 11:49:23 +0100 -rabbitmq-server (3.2.0-1) unstable; urgency=low +rabbitmq-server (3.3.0-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 23 Oct 2013 15:42:19 +0100 + -- Simon MacMullen Wed, 02 Apr 2014 14:23:14 +0100 -rabbitmq-server (3.1.4-1) unstable; urgency=low +rabbitmq-server (3.2.4-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 07 Aug 2013 15:16:28 +0100 + -- Simon MacMullen Mon, 03 Mar 2014 14:50:18 +0000 -rabbitmq-server (3.1.3-1) unstable; urgency=low +rabbitmq-server (3.2.3-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 27 Jun 2013 14:06:11 +0100 + -- Emile Joubert Thu, 23 Jan 2014 14:46:37 +0000 -rabbitmq-server (3.1.2-1) unstable; urgency=low +rabbitmq-server (3.2.2-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 25 Jun 2013 11:28:52 +0100 + -- Emile Joubert Tue, 10 Dec 2013 16:08:08 +0000 -rabbitmq-server (3.1.1-1) unstable; urgency=low +rabbitmq-server (3.2.0-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 28 May 2013 11:15:13 +0100 + -- Emile Joubert Wed, 23 Oct 2013 12:44:10 +0100 -rabbitmq-server (3.1.0-1) unstable; urgency=low +rabbitmq-server (3.1.5-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 02 May 2013 11:19:31 +0100 + -- Simon MacMullen Thu, 15 Aug 2013 11:03:13 +0100 -rabbitmq-server (3.0.4-1) unstable; urgency=low +rabbitmq-server (3.1.3-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 13 Mar 2013 10:53:18 +0000 + -- Tim Watson Tue, 25 Jun 2013 15:01:12 +0100 -rabbitmq-server (3.0.4-1) unstable; urgency=low +rabbitmq-server (3.1.2-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 13 Mar 2013 10:53:18 +0000 + -- Tim Watson Mon, 24 Jun 2013 11:16:41 +0100 -rabbitmq-server (3.0.3-1) unstable; urgency=low +rabbitmq-server (3.1.1-1) unstable; urgency=low - * New upstream release + * Test release - -- Emile Joubert Thu, 07 Mar 2013 10:03:31 +0000 + -- Tim Watson Mon, 20 May 2013 16:21:20 +0100 -rabbitmq-server (3.0.2-1) unstable; urgency=low +rabbitmq-server (3.1.0-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 31 Jan 2013 15:28:12 +0000 + -- Simon MacMullen Wed, 01 May 2013 11:57:58 +0100 rabbitmq-server (3.0.1-1) unstable; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 11 Dec 2012 15:47:52 +0000 + -- Simon MacMullen Tue, 11 Dec 2012 11:29:55 +0000 rabbitmq-server (3.0.0-1) unstable; urgency=low - * New upstream release - - -- Emile Joubert Mon, 19 Nov 2012 11:42:31 +0000 - -rabbitmq-server (2.8.7-1) unstable; urgency=low - - * New upstream release - - -- Emile Joubert Thu, 27 Sep 2012 16:28:21 +0100 - -rabbitmq-server (2.8.6-1) unstable; urgency=low - - * New upstream release + * New Upstream Release - -- Emile Joubert Wed, 22 Aug 2012 13:28:21 +0100 + -- Simon MacMullen Fri, 16 Nov 2012 14:15:29 +0000 -rabbitmq-server (2.8.5-1) unstable; urgency=low +rabbitmq-server (2.7.1-1) natty; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 02 Aug 2012 16:12:21 +0100 + -- Steve Powell Fri, 16 Dec 2011 12:12:36 +0000 -rabbitmq-server (2.8.4-1) unstable; urgency=low +rabbitmq-server (2.7.0-1) natty; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Fri, 22 Jun 2012 17:48:28 +0100 + -- Steve Powell Tue, 08 Nov 2011 16:47:50 +0000 -rabbitmq-server (2.8.3-1) unstable; urgency=low +rabbitmq-server (2.6.1-1) natty; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Thu, 21 Jun 2012 13:38:57 +0100 + -- Tim Fri, 09 Sep 2011 14:38:45 +0100 -rabbitmq-server (2.8.2-2) unstable; urgency=low +rabbitmq-server (2.6.0-1) natty; urgency=low - * Add version numbers to plugins + * New Upstream Release - -- Emile Joubert Tue, 01 May 2012 10:48:57 +0100 + -- Tim Fri, 26 Aug 2011 16:29:40 +0100 -rabbitmq-server (2.8.2-1) unstable; urgency=low +rabbitmq-server (2.5.1-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Mon, 30 Apr 2012 14:07:32 +0100 + -- Simon MacMullen Mon, 27 Jun 2011 11:21:49 +0100 -rabbitmq-server (2.8.1-1) unstable; urgency=low +rabbitmq-server (2.5.0-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Fri, 23 Mar 2012 10:05:24 +0000 + -- Thu, 09 Jun 2011 07:20:29 -0700 -rabbitmq-server (2.8.0-1) unstable; urgency=low +rabbitmq-server (2.4.1-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- Emile Joubert Tue, 20 Mar 2012 11:55:10 +0000 + -- Alexandru Scvortov Thu, 07 Apr 2011 16:49:22 +0100 -rabbitmq-server (2.6.1-2) unstable; urgency=low +rabbitmq-server (2.4.0-1) lucid; urgency=low - * Add DM-Upload-Allowed flag to control file to allow Maintainer uploads + * New Upstream Release - -- John Leuner Mon, 19 Mar 2012 21:13:54 +0200 + -- Alexandru Scvortov Tue, 22 Mar 2011 17:34:31 +0000 -rabbitmq-server (2.6.1-1) unstable; urgency=low +rabbitmq-server (2.3.1-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Tue, 27 Sep 2011 17:53:57 +0200 + -- Simon MacMullen Thu, 03 Feb 2011 12:43:56 +0000 -rabbitmq-server (2.5.0-1) unstable; urgency=low +rabbitmq-server (2.3.0-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Thu, 16 Jun 2011 09:55:40 +0200 + -- Simon MacMullen Tue, 01 Feb 2011 12:52:16 +0000 -rabbitmq-server (2.4.1-1) unstable; urgency=low +rabbitmq-server (2.2.0-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Sat, 09 Apr 2011 09:34:06 +0200 + -- Rob Harrop Mon, 29 Nov 2010 12:24:48 +0000 -rabbitmq-server (2.4.0-1) unstable; urgency=low +rabbitmq-server (2.1.1-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Wed, 23 Mar 2011 21:11:17 +0200 + -- Vlad Alexandru Ionescu Tue, 19 Oct 2010 17:20:10 +0100 -rabbitmq-server (2.3.1-1) unstable; urgency=low +rabbitmq-server (2.1.0-1) lucid; urgency=low - * New upstream release, closes: #611253 + * New Upstream Release - -- John Leuner Sat, 05 Feb 2011 10:21:16 +0200 + -- Marek Majkowski Tue, 14 Sep 2010 14:20:17 +0100 -rabbitmq-server (2.2.0-1) unstable; urgency=low +rabbitmq-server (2.0.0-1) karmic; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Thu, 02 Dec 2010 20:41:53 +0200 + -- Michael Bridgen Mon, 23 Aug 2010 14:55:39 +0100 -rabbitmq-server (2.1.0-1) unstable; urgency=low +rabbitmq-server (1.8.1-1) lucid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Mon, 27 Sep 2010 20:28:06 +0200 + -- Emile Joubert Wed, 14 Jul 2010 15:05:24 +0100 -rabbitmq-server (2.0.0-2) unstable; urgency=low +rabbitmq-server (1.8.0-1) intrepid; urgency=low - * Fix various scripts that were not updated correctly in - - the 2.0.0-1 package, closes: #594724 + * New Upstream Release - -- John Leuner Thu, 02 Sep 2010 18:01:37 +0200 + -- Matthew Sackman Tue, 15 Jun 2010 12:48:48 +0100 -rabbitmq-server (2.0.0-1) unstable; urgency=low +rabbitmq-server (1.7.2-1) intrepid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Sat, 28 Aug 2010 11:21:48 +0200 + -- Matthew Sackman Mon, 15 Feb 2010 15:54:47 +0000 -rabbitmq-server (1.8.1-1) unstable; urgency=low +rabbitmq-server (1.7.1-1) intrepid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Sun, 01 Aug 2010 15:47:46 +0200 + -- Matthew Sackman Fri, 22 Jan 2010 14:14:29 +0000 -rabbitmq-server (1.8.0-1) unstable; urgency=low +rabbitmq-server (1.7.0-1) intrepid; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Thu, 24 Jun 2010 18:43:04 +0200 + -- David Wragg Mon, 05 Oct 2009 13:44:41 +0100 -rabbitmq-server (1.7.0-3) unstable; urgency=low +rabbitmq-server (1.6.0-1) hardy; urgency=low - * Add missing entries in rabbitmq-server.init + * New Upstream Release - -- John Leuner Sun, 25 Oct 2009 10:21:25 +0200 + -- Matthias Radestock Tue, 16 Jun 2009 15:02:58 +0100 -rabbitmq-server (1.7.0-2) unstable; urgency=low +rabbitmq-server (1.5.5-1) hardy; urgency=low - * moved debian/init.d to rabbitmq-server.init - * included fixes to rabbitmq-script-wrapper + * New Upstream Release - -- John Leuner Wed, 14 Oct 2009 12:23:52 +0200 + -- Matthias Radestock Tue, 19 May 2009 09:57:54 +0100 -rabbitmq-server (1.7.0-1) unstable; urgency=low +rabbitmq-server (1.5.4-1) hardy; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Sat, 10 Oct 2009 13:28:39 +0200 + -- Matthias Radestock Mon, 06 Apr 2009 09:19:32 +0100 -rabbitmq-server (1.6.0-1) unstable; urgency=low +rabbitmq-server (1.5.3-1) hardy; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Sat, 20 Jun 2009 12:22:17 +0200 + -- Tony Garnock-Jones Tue, 24 Feb 2009 18:23:33 +0000 -rabbitmq-server (1.5.5-3) unstable; urgency=low +rabbitmq-server (1.5.2-1) hardy; urgency=low - * debian/control: Reduce Erlang dependencies to just - erlang-mnesia and erlang-os-mon, closes: #532867 + * New Upstream Release - -- John Leuner Tue, 16 Jun 2009 14:15:20 +0200 + -- Tony Garnock-Jones Mon, 23 Feb 2009 16:03:38 +0000 -rabbitmq-server (1.5.5-2) unstable; urgency=low +rabbitmq-server (1.5.1-1) hardy; urgency=low - * Include updates to debian package by rabbit team: - - quiet log rotate - - update build-depends and depends for new erlang packages - - debian/watch file - - add rabbitmq-script-wrapper - - update init.d scripts - - clean /etc/rabbitmq in postrm + * New Upstream Release - -- John Leuner Wed, 03 Jun 2009 12:23:50 +0200 + -- Simon MacMullen Mon, 19 Jan 2009 15:46:13 +0000 -rabbitmq-server (1.5.5-1) unstable; urgency=low +rabbitmq-server (1.5.0-1) testing; urgency=low - * New upstream release + * New Upstream Release - -- John Leuner Tue, 02 Jun 2009 12:53:32 +0200 + -- Matthias Radestock Wed, 17 Dec 2008 18:23:47 +0000 -rabbitmq-server (1.5.4-4) unstable; urgency=low +rabbitmq-server (1.4.0-1) testing; urgency=low - * Add new dependency on erlang-os-mon to work with new erlang packages in - debian + * New Upstream Release - -- John Leuner Mon, 11 May 2009 21:20:04 +0200 + -- Tony Garnock-Jones Thu, 24 Jul 2008 13:21:48 +0100 -rabbitmq-server (1.5.4-3) unstable; urgency=low +rabbitmq-server (1.3.0-1) testing; urgency=low - * Previous partial upload failed + * New Upstream Release - -- John Leuner Fri, 10 Apr 2009 20:25:51 +0200 + -- Adrien Pierard Mon, 03 Mar 2008 15:34:38 +0000 -rabbitmq-server (1.5.4-2) unstable; urgency=low +rabbitmq-server (1.2.0-2) testing; urgency=low - * Fix incorrect changed-by field in .changes file + * Fixed rabbitmqctl wrapper script - -- John Leuner Fri, 10 Apr 2009 19:40:04 +0200 + -- Simon MacMullen Fri, 05 Oct 2007 11:55:00 +0100 -rabbitmq-server (1.5.4-1) unstable; urgency=low +rabbitmq-server (1.2.0-1) testing; urgency=low * New upstream release - -- John Leuner Fri, 10 Apr 2009 17:54:21 +0200 - -rabbitmq-server (1.5.0-5) unstable; urgency=low - - * Include the full license for amqp-0.8.json in debian/copyright + -- Simon MacMullen Wed, 26 Sep 2007 11:49:26 +0100 - -- John Leuner Fri, 27 Feb 2009 16:16:54 +0200 +rabbitmq-server (1.1.1-1) testing; urgency=low -rabbitmq-server (1.5.0-4) unstable; urgency=low + * New upstream release - * Clarify and explicitly list the license and copyright for - codegen/amqp-0.8.json - - * Explicitly list the authors and copyright for the rest of the codebase - at the top of debian/copyright - - * Clarify the copyright of the files in src/tcp_* . The rabbitmq authors have - confirmed that they are the original authors of this code and that the - files at http://code.google.com/p/cacherl/ were taken without their - knowledge from the rabbitmq project. (Comparing the commit dates in version - control shows that cacherl is newer) + -- Simon MacMullen Wed, 29 Aug 2007 12:03:15 +0100 - -- John Leuner Wed, 25 Feb 2009 13:10:15 +0200 +rabbitmq-server (1.1.0-alpha-2) testing; urgency=low -rabbitmq-server (1.5.0-3) unstable; urgency=low + * Fixed erlang-nox dependency - * Previous changelog entry had an incorrect Maintainer name + -- Simon MacMullen Thu, 02 Aug 2007 11:27:13 +0100 - -- John Leuner Wed, 28 Jan 2009 16:45:33 +0200 +rabbitmq-server (1.1.0-alpha-1) testing; urgency=low -rabbitmq-server (1.5.0-2) unstable; urgency=low + * New upstream release - * Reupload package to unstable. Mistakenly uploaded to testing last time, closes: #507902 + -- Simon MacMullen Fri, 20 Jul 2007 18:17:33 +0100 - -- John Leuner Mon, 19 Jan 2009 17:38:43 +0200 +rabbitmq-server (1.0.0-alpha-1) unstable; urgency=low -rabbitmq-server (1.5.0-1) testing; urgency=low + * Initial release - * New Upstream Release - * First Debian upload, closes: #507902 + -- Tony Garnock-Jones Wed, 31 Jan 2007 19:06:33 +0000 - -- John Leuner Wed, 17 Dec 2008 18:23:47 +0000 diff --git a/debian/control b/debian/control index 912f8a8..cf9f8fa 100644 --- a/debian/control +++ b/debian/control @@ -1,37 +1,24 @@ Source: rabbitmq-server Section: net Priority: extra -Maintainer: PKG OpenStack -Uploaders: James Page , - Thomas Goirand , -Build-Depends: debhelper (>= 9~), - dh-python, - dh-systemd (>= 1.5), - erlang-dev, - erlang-nox (>= 1:13.b.3), - erlang-src (>= 1:13.b.3), - git, - python-simplejson, - python-all, - unzip, - xmlto, - xsltproc, - zip -Build-Depends-Indep: rsync, -Standards-Version: 3.9.8 -Vcs-Browser: https://anonscm.debian.org/cgit/openstack/rabbitmq-server.git/ -Vcs-Git: https://anonscm.debian.org/git/openstack/rabbitmq-server.git -Homepage: http://www.rabbitmq.com/ +Maintainer: RabbitMQ Team +Uploaders: Michael Klishin , + Karl Nilsson , + Jean-Sébastien Pédron +Build-Depends: debhelper (>= 9), + dh-systemd (>= 1.5), + erlang-dev, erlang-src, + python-simplejson, + xmlto, + xsltproc, + erlang-nox (>= 1:16.b.3) | esl-erlang, + zip, + rsync +Standards-Version: 3.9.4 Package: rabbitmq-server Architecture: all -Depends: adduser, - erlang-nox (>= 1:13.b.3) | esl-erlang, - lsb-base, - logrotate, - ${misc:Depends}, - ${python:Depends}, -Description: AMQP server written in Erlang - RabbitMQ is an implementation of AMQP, the emerging standard for high - performance enterprise messaging. The RabbitMQ server is a robust and - scalable implementation of an AMQP broker. +Depends: erlang-nox (>= 1:16.b.3) | esl-erlang, adduser, logrotate, socat, init-system-helpers (>= 1.13~), erlang-base-hipe +Description: Multi-protocol messaging broker + RabbitMQ is an open source multi-protocol messaging broker. +Homepage: http://www.rabbitmq.com/ diff --git a/debian/copyright b/debian/copyright index 5bb9b3b..521b903 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,565 +1,52 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: RabbitMQ -Source: http://www.rabbitmq.com/ +Upstream-Name: rabbitmq-server +Upstream-Contact: Jean-Sébastien Pédron +Source: https://github.com/rabbitmq/rabbitmq-server Files: * -Copyright: (c) 2007-2014 GoPivotal, Inc. +Copyright: 2007-2015 Pivotal Software, Inc. License: MPL-1.1 -Files: deps/rabbitmq_codegen/amqp-rabbitmq-*.json -Copyright: (c) 2008-2013, GoPivotal Inc. -License: Expat - -Files: deps/rabbitmq_management/priv/www/js/jquery*.js -Copyright: (c) 2010 John Resig -License: Expat -Comments: Downloaded from http://jquery.com/ - -Files: deps/rabbitmq_management/priv/www/js/ejs* - deps/rabbitmq_management/priv/www/js/tmpl/* -Copyright: (c) 2007, Edward Benson -License: Expat -Comments: downloaded from http://embeddedjs.com/ - -Files: deps/rabbitmq_management/priv/www/js/sammy*.js -Copyright: (c) 2008 Aaron Quint, Quirkey NYC, LLC -License: Expat -Comments: Downloaded from http://code.quirkey.com/sammy/ - -Files: deps/rabbitmq_management/priv/www/js/excanvas*.js -Copyright: (c) 2006, Google Inc -License: Apache-2.0 -Comments: Downloaded from https://github.com/arv/explorercanvas - -Files: deps/rabbitmq_management/priv/www/js/jquery.flot*.js -Copyright: (c) 2007-2013, IOLA and Ole Laursen -License: Expat -Comments: Downloaded from http://www.flotcharts.org/ - -Files: deps/webmachine/* -Copyright: (c) Basho Technologies -License: Apache-2.0 -Comments: Downloaded from http://webmachine.basho.com/ - -Files: deps/mochiweb/* -Copyright: (c) 2007, Mochi Media, Inc. -License: Expat -Comments: Downloaded from http://github.com/mochi/mochiweb/ - -Files: - deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix*.js -Copyright: (c) 2011, Brandon Jones -License: BSD-2-Clause -Comments: Downloaded from http://code.google.com/p/glmatrix/ - -Files: deps/rabbit_common/src/ec_semver.erl - deps/rabbit_common/src/ec_semver_parser.erl -Copyright: (c) 2011 Erlware, LLC -License: Expat - -Files: debian/* -Copyright: (c) 2007-2013, GoPivotal, Inc. - (c) 2007, Tony Garnock-Jones - (c) 2014, Blair Hester - (c) 2012-2014, Emile Joubert - (c) 2008-2012, John Leuner - (c) 2015, Antonio Terceiro - (c) 2014-2016, James Page - (c) 2014-2016, Thomas Goirand -License: MPL-1.1 - -License: Expat - Permission is hereby granted, free of charge, to any person obtaining a copy - of this file (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." - -License: BSD-2-Clause - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - . - 1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - . - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - . - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE." +Files: src/mochinum.erl deps/rabbit_common/src/mochijson2.erl +Copyright: 2007 Mochi Media, Inc. +License: MIT License: MPL-1.1 - MOZILLA PUBLIC LICENSE Version 1.1 - 1. Definitions. - . - 1.0.1. "Commercial Use" means distribution or otherwise making the Covered - Code available to a third party. - . - 1.1. "Contributor" means each entity that creates or contributes to the - creation of Modifications. - . - 1.2. "Contributor Version" means the combination of the Original Code, prior - Modifications used by a Contributor, and the Modifications made by that - particular Contributor. - . - 1.3. "Covered Code" means the Original Code or Modifications or the - combination of the Original Code and Modifications, in each case including - portions thereof. - . - 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted - in the software development community for the electronic transfer of data. - . - 1.5. "Executable" means Covered Code in any form other than Source Code. - . - 1.6. "Initial Developer" means the individual or entity identified as the - Initial Developer in the Source Code notice required by Exhibit A. - . - 1.7. "Larger Work" means a work which combines Covered Code or portions - thereof with code not governed by the terms of this License. - . - 1.8. "License" means this document. - . - 1.8.1. "Licensable" means having the right to grant, to the maximum extent - possible, whether at the time of the initial grant or subsequently acquired, - any and all of the rights conveyed herein. - . - 1.9. "Modifications" means any addition to or deletion from the substance or - structure of either the Original Code or any previous Modifications. When - Covered Code is released as a series of files, a Modification is: - . - A. Any addition to or deletion from the contents of a file containing - Original Code or previous Modifications. - . - B. Any new file that contains any part of the Original Code or previous - Modifications. - . - 1.10. "Original Code" means Source Code of computer software code which is - described in the Source Code notice required by Exhibit A as Original Code, - and which, at the time of its release under this License is not already - Covered Code governed by this License. - . - 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter - acquired, including without limitation, method, process, and apparatus - claims, in any patent Licensable by grantor. - . - 1.11. "Source Code" means the preferred form of the Covered Code for making - modifications to it, including all modules it contains, plus any associated - interface definition files, scripts used to control compilation and - installation of an Executable, or source code differential comparisons - against either the Original Code or another well known, available Covered - Code of the Contributor's choice. The Source Code can be in a compressed or - archival form, provided the appropriate decompression or de-archiving - software is widely available for no charge. - . - 1.12. "You" (or "Your") means an individual or a legal entity exercising - rights under, and complying with all of the terms of, this License or a - future version of this License issued under Section 6.1. For legal entities, - "You" includes any entity which controls, is controlled by, or is under - common control with You. For purposes of this definition, "control" means (a) - the power, direct or indirect, to cause the direction or management of such - entity, whether by contract or otherwise, or (b) ownership of more than fifty - percent (50%) of the outstanding shares or beneficial ownership of such - entity. - . - 2. Source Code License. - . - 2.1. The Initial Developer Grant. - The Initial Developer hereby grants You a world-wide, royalty-free, - non-exclusive license, subject to third party intellectual property claims: - . - (a) under intellectual property rights (other than patent or - trademark) Licensable by Initial Developer to use, reproduce, - modify, display, perform, sublicense and distribute the Original - Code (or portions thereof) with or without Modifications, and/or - as part of a Larger Work; and - . - (b) under Patents Claims infringed by the making, using or - selling of Original Code, to make, have made, use, practice, - sell, and offer for sale, and/or otherwise dispose of the - Original Code (or portions thereof). - . - (c) the licenses granted in this Section 2.1(a) and (b) are - effective on the date Initial Developer first distributes - Original Code under the terms of this License. - . - (d) Notwithstanding Section 2.1(b) above, no patent license is - granted: 1) for code that You delete from the Original Code; 2) - separate from the Original Code; or 3) for infringements caused - by: i) the modification of the Original Code or ii) the - combination of the Original Code with other software or devices. - . - 2.2. Contributor Grant. - Subject to third party intellectual property claims, each Contributor hereby - grants You a world-wide, royalty-free, non-exclusive license - . - (a) under intellectual property rights (other than patent or - trademark) Licensable by Contributor, to use, reproduce, modify, - display, perform, sublicense and distribute the Modifications - created by such Contributor (or portions thereof) either on an - unmodified basis, with other Modifications, as Covered Code - and/or as part of a Larger Work; and - . - (b) under Patent Claims infringed by the making, using, or - selling of Modifications made by that Contributor either alone - and/or in combination with its Contributor Version (or portions - of such combination), to make, use, sell, offer for sale, have - made, and/or otherwise dispose of: 1) Modifications made by that - Contributor (or portions thereof); and 2) the combination of - Modifications made by that Contributor with its Contributor - Version (or portions of such combination). - . - (c) the licenses granted in Sections 2.2(a) and 2.2(b) are - effective on the date Contributor first makes Commercial Use of - the Covered Code. - . - (d) Notwithstanding Section 2.2(b) above, no patent license is - granted: 1) for any code that Contributor has deleted from the - Contributor Version; 2) separate from the Contributor Version; - 3) for infringements caused by: i) third party modifications of - Contributor Version or ii) the combination of Modifications made - by that Contributor with other software (except as part of the - Contributor Version) or other devices; or 4) under Patent Claims - infringed by Covered Code in the absence of Modifications made by - that Contributor. - . - 3. Distribution Obligations. - . - 3.1. Application of License. - . - The Modifications which You create or to which You contribute are governed by - the terms of this License, including without limitation Section 2.2. The - Source Code version of Covered Code may be distributed only under the terms of - this License or a future version of this License released under Section 6.1, - and You must include a copy of this License with every copy of the Source Code - You distribute. You may not offer or impose any terms on any Source Code - version that alters or restricts the applicable version of this License or the - recipients' rights hereunder. However, You may include an additional document - offering the additional rights described in Section 3.5. - . - 3.2. Availability of Source Code. - . - Any Modification which You create or to which You contribute must be made - available in Source Code form under the terms of this License either on the - same media as an Executable version or via an accepted Electronic Distribution - Mechanism to anyone to whom you made an Executable version available; and if - made available via Electronic Distribution Mechanism, must remain available - for at least twelve (12) months after the date it initially became available, - or at least six (6) months after a subsequent version of that particular - Modification has been made available to such recipients. You are responsible - for ensuring that the Source Code version remains available even if the - Electronic Distribution Mechanism is maintained by a third party. - . - 3.3. Description of Modifications. - . - You must cause all Covered Code to which You contribute to contain a file - documenting the changes You made to create that Covered Code and the date of - any change. You must include a prominent statement that the Modification is - derived, directly or indirectly, from Original Code provided by the Initial - Developer and including the name of the Initial Developer in (a) the Source - Code, and (b) in any notice in an Executable version or related documentation - in which You describe the origin or ownership of the Covered Code. - . - 3.4. Intellectual Property Matters - . - (a) Third Party Claims. - . - If Contributor has knowledge that a license under a third party's - intellectual property rights is required to exercise the rights - granted by such Contributor under Sections 2.1 or 2.2, - Contributor must include a text file with the Source Code - distribution titled "LEGAL" which describes the claim and the - party making the claim in sufficient detail that a recipient will - know whom to contact. If Contributor obtains such knowledge after - the Modification is made available as described in Section 3.2, - Contributor shall promptly modify the LEGAL file in all copies - Contributor makes available thereafter and shall take other steps - (such as notifying appropriate mailing lists or newsgroups) - reasonably calculated to inform those who received the Covered - Code that new knowledge has been obtained. - . - (b) Contributor APIs. - . - If Contributor's Modifications include an application programming - interface and Contributor has knowledge of patent licenses which - are reasonably necessary to implement that API, Contributor must - also include this information in the LEGAL file. - . - (c) Representations. - . - Contributor represents that, except as disclosed pursuant to - Section 3.4(a) above, Contributor believes that Contributor's - Modifications are Contributor's original creation(s) and/or - Contributor has sufficient rights to grant the rights conveyed by - this License. - . - 3.5. Required Notices. - . - You must duplicate the notice in Exhibit A in each file of the Source - Code. If it is not possible to put such notice in a particular Source - Code file due to its structure, then You must include such notice in a - location (such as a relevant directory) where a user would be likely - to look for such a notice. If You created one or more Modification(s) - You may add your name as a Contributor to the notice described in - Exhibit A. You must also duplicate this License in any documentation - for the Source Code where You describe recipients' rights or ownership - rights relating to Covered Code. You may choose to offer, and to - charge a fee for, warranty, support, indemnity or liability - obligations to one or more recipients of Covered Code. However, You - may do so only on Your own behalf, and not on behalf of the Initial - Developer or any Contributor. You must make it absolutely clear than - any such warranty, support, indemnity or liability obligation is - offered by You alone, and You hereby agree to indemnify the Initial - Developer and every Contributor for any liability incurred by the - Initial Developer or such Contributor as a result of warranty, - support, indemnity or liability terms You offer. - . - 3.6. Distribution of Executable Versions. - . - You may distribute Covered Code in Executable form only if the - requirements of Section 3.1-3.5 have been met for that Covered Code, - and if You include a notice stating that the Source Code version of - the Covered Code is available under the terms of this License, - including a description of how and where You have fulfilled the - obligations of Section 3.2. The notice must be conspicuously included - in any notice in an Executable version, related documentation or - collateral in which You describe recipients' rights relating to the - Covered Code. You may distribute the Executable version of Covered - Code or ownership rights under a license of Your choice, which may - contain terms different from this License, provided that You are in - compliance with the terms of this License and that the license for the - Executable version does not attempt to limit or alter the recipient's - rights in the Source Code version from the rights set forth in this - License. If You distribute the Executable version under a different - license You must make it absolutely clear that any terms which differ - from this License are offered by You alone, not by the Initial - Developer or any Contributor. You hereby agree to indemnify the - Initial Developer and every Contributor for any liability incurred by - the Initial Developer or such Contributor as a result of any such - terms You offer. - . - 3.7. Larger Works. - . - You may create a Larger Work by combining Covered Code with other code - not governed by the terms of this License and distribute the Larger - Work as a single product. In such a case, You must make sure the - requirements of this License are fulfilled for the Covered Code. - . - 4. Inability to Comply Due to Statute or Regulation. - . - If it is impossible for You to comply with any of the terms of this - License with respect to some or all of the Covered Code due to - statute, judicial order, or regulation then You must: (a) comply with - the terms of this License to the maximum extent possible; and (b) - describe the limitations and the code they affect. Such description - must be included in the LEGAL file described in Section 3.4 and must - be included with all distributions of the Source Code. Except to the - extent prohibited by statute or regulation, such description must be - sufficiently detailed for a recipient of ordinary skill to be able to - understand it. - . - 5. Application of this License. - . - This License applies to code to which the Initial Developer has - attached the notice in Exhibit A and to related Covered Code. - . - 6. Versions of the License. - . - 6.1. New Versions. - . - Netscape Communications Corporation ("Netscape") may publish revised - and/or new versions of the License from time to time. Each version - will be given a distinguishing version number. - . - 6.2. Effect of New Versions. - . - Once Covered Code has been published under a particular version of the - License, You may always continue to use it under the terms of that - version. You may also choose to use such Covered Code under the terms - of any subsequent version of the License published by Netscape. No one - other than Netscape has the right to modify the terms applicable to - Covered Code created under this License. - . - 6.3. Derivative Works. - . - If You create or use a modified version of this License (which you may - only do in order to apply it to code which is not already Covered Code - governed by this License), You must (a) rename Your license so that - the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", - "MPL", "NPL" or any confusingly similar phrase do not appear in your - license (except to note that your license differs from this License) - and (b) otherwise make it clear that Your version of the license - contains terms which differ from the Mozilla Public License and - Netscape Public License. (Filling in the name of the Initial - Developer, Original Code or Contributor in the notice described in - Exhibit A shall not of themselves be deemed to be modifications of - this License.) - . - 7. DISCLAIMER OF WARRANTY. - . - COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, - WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, - WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF - DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. - THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE - IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, - YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE - COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER - OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF - ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. - . - 8. TERMINATION. - . - 8.1. This License and the rights granted hereunder will terminate - automatically if You fail to comply with terms herein and fail to cure - such breach within 30 days of becoming aware of the breach. All - sublicenses to the Covered Code which are properly granted shall - survive any termination of this License. Provisions which, by their - nature, must remain in effect beyond the termination of this License - shall survive. - . - 8.2. If You initiate litigation by asserting a patent infringement - claim (excluding declatory judgment actions) against Initial Developer - or a Contributor (the Initial Developer or Contributor against whom - You file such action is referred to as "Participant") alleging that: - . - (a) such Participant's Contributor Version directly or indirectly - infringes any patent, then any and all rights granted by such - Participant to You under Sections 2.1 and/or 2.2 of this License - shall, upon 60 days notice from Participant terminate prospectively, - unless if within 60 days after receipt of notice You either: (i) - agree in writing to pay Participant a mutually agreeable reasonable - royalty for Your past and future use of Modifications made by such - Participant, or (ii) withdraw Your litigation claim with respect to - the Contributor Version against such Participant. If within 60 days - of notice, a reasonable royalty and payment arrangement are not - mutually agreed upon in writing by the parties or the litigation claim - is not withdrawn, the rights granted by Participant to You under - Sections 2.1 and/or 2.2 automatically terminate at the expiration of - the 60 day notice period specified above. - . - (b) any software, hardware, or device, other than such Participant's - Contributor Version, directly or indirectly infringes any patent, then - any rights granted to You by such Participant under Sections 2.1(b) - and 2.2(b) are revoked effective as of the date You first made, used, - sold, distributed, or had made, Modifications made by that - Participant. - . - 8.3. If You assert a patent infringement claim against Participant - alleging that such Participant's Contributor Version directly or - indirectly infringes any patent where such claim is resolved (such as - by license or settlement) prior to the initiation of patent - infringement litigation, then the reasonable value of the licenses - granted by such Participant under Sections 2.1 or 2.2 shall be taken - into account in determining the amount or value of any payment or - license. - . - 8.4. In the event of termination under Sections 8.1 or 8.2 above, - all end user license agreements (excluding distributors and resellers) - which have been validly granted by You or any distributor hereunder - prior to termination shall survive termination. - . - 9. LIMITATION OF LIABILITY. - . - UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT - (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL - DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, - OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR - ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY - CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, - WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER - COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN - INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF - LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY - RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW - PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO - THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. - . - 10. U.S. GOVERNMENT END USERS. - . - The Covered Code is a "commercial item," as that term is defined in - 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer - software" and "commercial computer software documentation," as such - terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 - C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), - all U.S. Government End Users acquire Covered Code with only those - rights set forth herein. - . - 11. MISCELLANEOUS. - . - This License represents the complete agreement concerning subject - matter hereof. If any provision of this License is held to be - unenforceable, such provision shall be reformed only to the extent - necessary to make it enforceable. This License shall be governed by - California law provisions (except to the extent applicable law, if - any, provides otherwise), excluding its conflict-of-law provisions. - With respect to disputes in which at least one party is a citizen of, - or an entity chartered or registered to do business in the United - States of America, any litigation relating to this License shall be - subject to the jurisdiction of the Federal Courts of the Northern - District of California, with venue lying in Santa Clara County, - California, with the losing party responsible for costs, including - without limitation, court costs and reasonable attorneys' fees and - expenses. The application of the United Nations Convention on - Contracts for the International Sale of Goods is expressly excluded. - Any law or regulation which provides that the language of a contract - shall be construed against the drafter shall not apply to this - License. - . - 12. RESPONSIBILITY FOR CLAIMS. - . - As between Initial Developer and the Contributors, each party is - responsible for claims and damages arising, directly or indirectly, - out of its utilization of rights under this License and You agree to - work with Initial Developer and Contributors to distribute such - responsibility on an equitable basis. Nothing herein is intended or - shall be deemed to constitute any admission of liability. - . - 13. MULTIPLE-LICENSED CODE. - . - Initial Developer may designate portions of the Covered Code as - "Multiple-Licensed". "Multiple-Licensed" means that the Initial - Developer permits you to utilize portions of the Covered Code under - Your choice of the NPL or the alternative licenses, if any, specified - by the Initial Developer in the file described in Exhibit A. - . - EXHIBIT A -Mozilla Public License. - . - The contents of this file are subject to the Mozilla Public License Version - 1.1 (the "License"); you may not use this file except in compliance with the - License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ - . - Software distributed under the License is distributed on an "AS IS" basis, - WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for - the specific language governing rights and limitations under the License. - . - The Original Code is RabbitMQ. - . - The Initial Developer of the Original Code is GoPivotal, Inc. Copyright (c) - 2007-2014 GoPivotal, Inc. All rights reserved. - -License: Apache-2.0 - On Debian GNU/Linux system you can find the complete text of the - Apache-2.0 license in '/usr/share/common-licenses/Apache-2.0' + The contents of this file are subject to the Mozilla Public License + Version 1.1 (the "License"); you may not use this file except in + compliance with the License. You may obtain a copy of the License at + http://www.mozilla.org/MPL/ + . + Software distributed under the License is distributed on an "AS IS" + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + the License for the specific language governing rights and limitations + under the License + . + The Original Code is RabbitMQ + . + The Initial Developer of the Original Code is Pivotal Software, Inc. + Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. + +License: MIT + This is the MIT license + . + Copyright (c) 2007 Mochi Media, Inc + . + 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. diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..625b7d4 --- /dev/null +++ b/debian/dirs @@ -0,0 +1,9 @@ +usr/lib/rabbitmq/bin +usr/lib/erlang/lib +usr/sbin +usr/share/man +var/lib/rabbitmq/mnesia +var/log/rabbitmq +etc/logrotate.d +etc/rabbitmq + diff --git a/debian/gbp.conf b/debian/gbp.conf deleted file mode 100644 index 399a9f6..0000000 --- a/debian/gbp.conf +++ /dev/null @@ -1,11 +0,0 @@ -[DEFAULT] -upstream-branch = upstream -debian-branch = master -pristine-tar = True - -[buildpackage] -export-dir = ../build-area/ - -[dch] -id-length = 7 -meta-closes = Closes|LP diff --git a/debian/patches/native-code-location.patch b/debian/patches/native-code-location.patch new file mode 100644 index 0000000..d207454 --- /dev/null +++ b/debian/patches/native-code-location.patch @@ -0,0 +1,10 @@ +--- a/deps/rabbit/scripts/rabbitmq-server ++++ b/deps/rabbit/scripts/rabbitmq-server +@@ -152,6 +152,7 @@ start_rabbitmq_server() { + check_start_params && + RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ + exec ${ERL_DIR}erl \ ++ -pa /var/lib/rabbitmq/native-code \ + -pa ${RABBITMQ_SERVER_CODE_PATH} ${RABBITMQ_EBIN_ROOT} \ + ${RABBITMQ_START_RABBIT} \ + ${RABBITMQ_NAME_TYPE} ${RABBITMQ_NODENAME} \ diff --git a/debian/patches/series b/debian/patches/series new file mode 100644 index 0000000..8b5f59c --- /dev/null +++ b/debian/patches/series @@ -0,0 +1 @@ +native-code-location.patch diff --git a/debian/postinst b/debian/postinst new file mode 100755 index 0000000..cddeb99 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,63 @@ +#!/bin/sh +# postinst script for rabbitmq +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +# create rabbitmq group +if ! getent group rabbitmq >/dev/null; then + addgroup --system rabbitmq +fi + +# create rabbitmq user +if ! getent passwd rabbitmq >/dev/null; then + adduser --system --ingroup rabbitmq --home /var/lib/rabbitmq \ + --no-create-home --gecos "RabbitMQ messaging server" \ + --disabled-login rabbitmq +fi + +chown -R rabbitmq:rabbitmq /var/lib/rabbitmq +chown -R rabbitmq:rabbitmq /var/log/rabbitmq +chmod 750 /var/lib/rabbitmq/mnesia +chmod -R o-rwx,g-w /var/lib/rabbitmq/mnesia + +case "$1" in + configure) + if [ -f /etc/rabbitmq/rabbitmq.conf ] && \ + [ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then + mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf + fi + rabbitmqctl hipe_compile /var/lib/rabbitmq/native-code + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/postrm.in b/debian/postrm.in new file mode 100644 index 0000000..c2e9bbf --- /dev/null +++ b/debian/postrm.in @@ -0,0 +1,65 @@ +#!/bin/sh +# postrm script for rabbitmq +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +remove_plugin_traces() { + # Remove traces of plugins + rm -rf /var/lib/rabbitmq/plugins-scratch +} + +case "$1" in + purge) + rm -f /etc/default/rabbitmq + if [ -d /var/lib/rabbitmq ]; then + rm -r /var/lib/rabbitmq + fi + if [ -d /var/log/rabbitmq ]; then + rm -r /var/log/rabbitmq + fi + if [ -d /etc/rabbitmq ]; then + rm -r /etc/rabbitmq + fi + remove_plugin_traces + if getent passwd rabbitmq >/dev/null; then + # Stop epmd if run by the rabbitmq user + pkill -u rabbitmq epmd || : + fi + ;; + + remove|upgrade) + remove_plugin_traces + ;; + + failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/rabbitmq-env.conf b/debian/rabbitmq-env.conf deleted file mode 100644 index bebe2ab..0000000 --- a/debian/rabbitmq-env.conf +++ /dev/null @@ -1,13 +0,0 @@ -# Defaults to rabbit. This can be useful if you want to run more than one node -# per machine - RABBITMQ_NODENAME should be unique per erlang-node-and-machine -# combination. See the clustering on a single machine guide for details: -# http://www.rabbitmq.com/clustering.html#single-machine -#NODENAME=rabbit - -# By default RabbitMQ will bind to all interfaces, on IPv4 and IPv6 if -# available. Set this if you only want to bind to one network interface or# -# address family. -#NODE_IP_ADDRESS=127.0.0.1 - -# Defaults to 5672. -#NODE_PORT=5672 diff --git a/debian/rabbitmq-script-wrapper b/debian/rabbitmq-script-wrapper deleted file mode 100755 index a622ae2..0000000 --- a/debian/rabbitmq-script-wrapper +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/sh -## The contents of this file are subject to the Mozilla Public License -## Version 1.1 (the "License"); you may not use this file except in -## compliance with the License. You may obtain a copy of the License -## at http://www.mozilla.org/MPL/ -## -## Software distributed under the License is distributed on an "AS IS" -## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -## the License for the specific language governing rights and -## limitations under the License. -## -## The Original Code is RabbitMQ. -## -## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. -## - -# Escape spaces and quotes, because shell is revolting. -for arg in "$@" ; do - # Escape quotes in parameters, so that they're passed through cleanly. - arg=$(sed -e 's/"/\\"/g' <<-END - $arg - END - ) - CMDLINE="${CMDLINE} \"${arg}\"" -done - -cd /var/lib/rabbitmq - -SCRIPT=`basename $0` - -if [ `id -u` = `id -u rabbitmq` -a "$SCRIPT" = "rabbitmq-server" ] ; then - /usr/lib/rabbitmq/bin/rabbitmq-server "$@" > "/var/log/rabbitmq/startup_log" 2> "/var/log/rabbitmq/startup_err" -elif [ `id -u` = `id -u rabbitmq` -o "$SCRIPT" = "rabbitmq-plugins" ] ; then - if [ -f $PWD/.erlang.cookie ] ; then - export HOME=. - fi - /usr/lib/rabbitmq/bin/${SCRIPT} "$@" -elif [ `id -u` = 0 ] ; then - su rabbitmq -s /bin/sh -c "/usr/lib/rabbitmq/bin/${SCRIPT} ${CMDLINE}" -else - /usr/lib/rabbitmq/bin/${SCRIPT} - echo - echo "Only root or rabbitmq should run ${SCRIPT}" - echo - exit 1 -fi diff --git a/debian/rabbitmq-server-wait b/debian/rabbitmq-server-wait deleted file mode 100755 index cdf53e5..0000000 --- a/debian/rabbitmq-server-wait +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh -e -## The contents of this file are subject to the Mozilla Public License -## Version 1.1 (the "License"); you may not use this file except in -## compliance with the License. You may obtain a copy of the License -## at http://www.mozilla.org/MPL/ -## -## Software distributed under the License is distributed on an "AS IS" -## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -## the License for the specific language governing rights and -## limitations under the License. -## -## The Original Code is RabbitMQ. -## -## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. -## - -# Get default settings with user overrides for (RABBITMQ_) -# Non-empty defaults should be set in rabbitmq-env -. `dirname $0`/rabbitmq-env - -/usr/lib/rabbitmq/bin/rabbitmqctl wait $RABBITMQ_PID_FILE diff --git a/debian/rabbitmq-server.default b/debian/rabbitmq-server.default index 1da9985..3eebe2f 100644 --- a/debian/rabbitmq-server.default +++ b/debian/rabbitmq-server.default @@ -6,7 +6,6 @@ # to handle many simultaneous connections. Refer to the system # documentation for ulimit (in man bash) for more information. # -#ulimit -n 1024 # Default value is 1024, but it's absolutely unreasonable default in a # modern world, as rabbitmq consumes file descriptors for everything: # for client connections, for per-queue files, etc. Its documentation diff --git a/debian/rabbitmq-server.dirs b/debian/rabbitmq-server.dirs deleted file mode 100644 index e6127a0..0000000 --- a/debian/rabbitmq-server.dirs +++ /dev/null @@ -1,3 +0,0 @@ -usr/lib/erlang/lib -var/lib/rabbitmq/mnesia -var/log/rabbitmq diff --git a/debian/rabbitmq-server.docs b/debian/rabbitmq-server.docs new file mode 100644 index 0000000..6055402 --- /dev/null +++ b/debian/rabbitmq-server.docs @@ -0,0 +1,2 @@ +deps/rabbit/docs/rabbitmq.config.example +deps/rabbit/docs/set_rabbitmq_policy.sh.example diff --git a/debian/rabbitmq-server.init b/debian/rabbitmq-server.init index 1be33b0..fce2d16 100644 --- a/debian/rabbitmq-server.init +++ b/debian/rabbitmq-server.init @@ -1,4 +1,11 @@ #!/bin/sh +# +# rabbitmq-server RabbitMQ broker +# +# chkconfig: - 80 05 +# description: Manages RabbitMQ server +# + ### BEGIN INIT INFO # Provides: rabbitmq-server # Required-Start: $remote_fs $network @@ -6,19 +13,18 @@ # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Description: RabbitMQ broker -# Short-Description: Enable AMQP service provided by RabbitMQ broker +# Short-Description: Manages RabbitMQ server ### END INIT INFO PATH=/sbin:/usr/sbin:/bin:/usr/bin NAME=rabbitmq-server DAEMON=/usr/sbin/${NAME} CONTROL=/usr/sbin/rabbitmqctl -DESC="RabbitMQ Messaging Server" +DESC="message broker" USER=rabbitmq ROTATE_SUFFIX= -INIT_LOG_DIR=/var/log/rabbitmq PID_FILE=/var/run/rabbitmq/pid - +RABBITMQ_ENV=/usr/lib/rabbitmq/bin/rabbitmq-env test -x $DAEMON || exit 0 test -x $CONTROL || exit 0 @@ -28,6 +34,9 @@ set -e [ -f /etc/default/${NAME} ] && . /etc/default/${NAME} +RABBITMQ_SCRIPTS_DIR=$(dirname "$RABBITMQ_ENV") +. "$RABBITMQ_ENV" + . /lib/lsb/init-functions . /lib/init/vars.sh @@ -53,7 +62,7 @@ start_rabbitmq () { set +e RABBITMQ_PID_FILE=$PID_FILE start-stop-daemon --quiet \ --chuid rabbitmq --start --exec $DAEMON \ - --pidfile "$RABBITMQ_PID_FILE" --background + --pidfile "$PID_FILE" --background $CONTROL wait $PID_FILE >/dev/null 2>&1 RETVAL=$? set -e @@ -69,7 +78,9 @@ stop_rabbitmq () { status_rabbitmq quiet if [ $RETVAL = 0 ] ; then set +e - $CONTROL stop ${PID_FILE} > ${INIT_LOG_DIR}/shutdown_log 2> ${INIT_LOG_DIR}/shutdown_err + $CONTROL stop ${PID_FILE} \ + > ${RABBITMQ_LOG_BASE}/shutdown_log \ + 2> ${RABBITMQ_LOG_BASE}/shutdown_err RETVAL=$? set -e if [ $RETVAL = 0 ] ; then @@ -136,7 +147,7 @@ start_stop_end() { RETVAL=0 ;; *) - log_warning_msg "FAILED - check ${INIT_LOG_DIR}/startup_\{log, _err\}" + log_warning_msg "FAILED - check ${RABBITMQ_LOG_BASE}/startup_\{log, _err\}" log_end_msg 1 ;; esac diff --git a/debian/rabbitmq-server.install b/debian/rabbitmq-server.install deleted file mode 100644 index 98a9ad3..0000000 --- a/debian/rabbitmq-server.install +++ /dev/null @@ -1,4 +0,0 @@ -debian/rabbitmq-env.conf /usr/share/rabbitmq -debian/rabbitmq-script-wrapper /usr/lib/rabbitmq/bin -debian/rabbitmq-server-wait /usr/lib/rabbitmq/bin -deps/rabbitmq_management/bin/rabbitmqadmin /usr/bin diff --git a/debian/rabbitmq-server.links b/debian/rabbitmq-server.links deleted file mode 100644 index cf8e8a7..0000000 --- a/debian/rabbitmq-server.links +++ /dev/null @@ -1,3 +0,0 @@ -/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmq-plugins -/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmq-server -/usr/lib/rabbitmq/bin/rabbitmq-script-wrapper /usr/sbin/rabbitmqctl diff --git a/debian/rabbitmq-server.manpages b/debian/rabbitmq-server.manpages new file mode 100644 index 0000000..f2ca632 --- /dev/null +++ b/debian/rabbitmq-server.manpages @@ -0,0 +1,4 @@ +deps/rabbit/docs/rabbitmq-env.conf.5 +deps/rabbit/docs/rabbitmq-plugins.1 +deps/rabbit/docs/rabbitmq-server.1 +deps/rabbit/docs/rabbitmqctl.1 diff --git a/debian/rabbitmq-server.postinst b/debian/rabbitmq-server.postinst deleted file mode 100644 index efcd88e..0000000 --- a/debian/rabbitmq-server.postinst +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -set -e - -if [ "$1" = "configure" ] || [ "$1" = "reconfigure" ] ; then - # create rabbitmq group - if ! getent group rabbitmq >/dev/null; then - addgroup --system rabbitmq - fi - - # create rabbitmq user - if ! getent passwd rabbitmq >/dev/null; then - adduser --system \ - --ingroup rabbitmq \ - --home /var/lib/rabbitmq \ - --no-create-home \ - --gecos "RabbitMQ messaging server" \ - --disabled-login rabbitmq - fi - - mkdir -p /etc/rabbitmq - chown rabbitmq:rabbitmq /etc/rabbitmq - if [ -f /etc/rabbitmq/rabbitmq.conf ] && [ ! -f /etc/rabbitmq/rabbitmq-env.conf ]; then - mv /etc/rabbitmq/rabbitmq.conf /etc/rabbitmq/rabbitmq-env.conf - chown rabbitmq:rabbitmq /etc/rabbitmq/rabbitmq-env.conf - fi - if [ -r /usr/share/rabbitmq/rabbitmq-env.conf ] && ! [ -e /etc/rabbitmq/rabbitmq-env.conf ] ; then - install -m 0644 -o rabbitmq -g rabbitmq /usr/share/rabbitmq/rabbitmq-env.conf /etc/rabbitmq/rabbitmq-env.conf - fi - if [ -f /etc/rabbitmq/enabled_plugins ] ; then - chown rabbitmq:rabbitmq /etc/rabbitmq/enabled_plugins - fi - - mkdir -p /var/lib/rabbitmq/mnesia - chmod 750 /var/lib/rabbitmq/mnesia - chmod -R o-rwx,g-w /var/lib/rabbitmq/mnesia - - chown -R rabbitmq:rabbitmq /var/lib/rabbitmq - chown -R rabbitmq:rabbitmq /var/log/rabbitmq - -fi - -#DEBHELPER# - -exit 0 diff --git a/debian/rabbitmq-server.postrm b/debian/rabbitmq-server.postrm deleted file mode 100644 index 74b6427..0000000 --- a/debian/rabbitmq-server.postrm +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/sh - -set -e - -if [ "${1}" = "remove" ] || [ "${1}" = "upgrade" ] ; then - # Remove traces of plugins - rm -rf /var/lib/rabbitmq/plugins-scratch -fi - -if [ "${1}" = "purge" ] ; then - rm -f /etc/default/rabbitmq - if [ -d /var/lib/rabbitmq ]; then - rm -rf /var/lib/rabbitmq - fi - if [ -d /var/log/rabbitmq ]; then - rm -rf /var/log/rabbitmq - fi - if [ -d /etc/rabbitmq ]; then - rm -rf /etc/rabbitmq - fi - - if getent passwd rabbitmq >/dev/null; then - # Stop epmd if run by the rabbitmq user - pkill -u rabbitmq epmd || : - fi -fi - -#DEBHELPER# - -exit 0 diff --git a/debian/rabbitmq-server.service b/debian/rabbitmq-server.service index faa73c1..1aa6549 100644 --- a/debian/rabbitmq-server.service +++ b/debian/rabbitmq-server.service @@ -1,15 +1,18 @@ +# systemd unit example [Unit] -Description=RabbitMQ Messaging Server -After=network.target +Description=RabbitMQ broker +After=network.target epmd@0.0.0.0.socket +Wants=network.target epmd@0.0.0.0.socket [Service] -Type=simple +Type=notify User=rabbitmq -SyslogIdentifier=rabbitmq -LimitNOFILE=65536 -ExecStart=/usr/sbin/rabbitmq-server -ExecStartPost=/usr/lib/rabbitmq/bin/rabbitmq-server-wait -ExecStop=/usr/sbin/rabbitmqctl stop +Group=rabbitmq +NotifyAccess=all +TimeoutStartSec=3600 +WorkingDirectory=/var/lib/rabbitmq +ExecStart=/usr/lib/rabbitmq/bin/rabbitmq-server +ExecStop=/usr/lib/rabbitmq/bin/rabbitmqctl stop [Install] WantedBy=multi-user.target diff --git a/debian/rules b/debian/rules index 9becb86..a6decd3 100755 --- a/debian/rules +++ b/debian/rules @@ -1,22 +1,26 @@ #!/usr/bin/make -f # -*- makefile -*- -DEB_DESTDIR=debian/rabbitmq-server +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +DEB_DESTDIR = debian/rabbitmq-server VERSION = $(shell dpkg-parsechangelog | awk '/^Version:/ {version=$$0; sub(/Version: /, "", version); sub(/-.*/, "", version); print version;}') unexport DEPS_DIR %: - dh $@ --parallel --with python2,systemd + dh $@ --parallel --with systemd override_dh_auto_clean: - $(MAKE) clean distclean-manpages + $(MAKE) clean clean-unpacked-source-dist distclean-manpages + rm -rf .erlang.mk override_dh_auto_build: $(MAKE) dist manpages override_dh_auto_test: - echo "Disabled tests, as they download from github" + @: export PREFIX RMQ_ROOTDIR @@ -24,13 +28,13 @@ override_dh_auto_install: PREFIX = /usr override_dh_auto_install: RMQ_ROOTDIR = $(PREFIX)/lib/rabbitmq override_dh_auto_install: RMQ_ERLAPP_DIR = $(RMQ_ROOTDIR)/lib/rabbitmq_server-$(VERSION) override_dh_auto_install: - dh_auto_install - #dh_auto_install -- DESTDIR=$(DEB_DESTDIR) PREFIX=/usr MAN_DIR=$(DEB_DESTDIR)/usr/share/man + dh_auto_install -- VERSION=$(VERSION) - $(MAKE) install-bin DESTDIR=$(DEB_DESTDIR) + $(MAKE) install-bin DESTDIR=$(DEB_DESTDIR) VERSION=$(VERSION) + sed -e 's|@RABBIT_LIB@|$(RMQ_ERLAPP_DIR)|g' \ + < debian/postrm.in > debian/postrm - mkdir -p debian/rabbitmq-server/usr/sbin sed -e 's|@SU_RABBITMQ_SH_C@|su rabbitmq -s /bin/sh -c|' \ -e 's|@STDOUT_STDERR_REDIRECTION@|> "$$RABBITMQ_LOG_BASE/startup_log" 2> "$$RABBITMQ_LOG_BASE/startup_err"|' \ < scripts/rabbitmq-script-wrapper \ @@ -38,29 +42,27 @@ override_dh_auto_install: chmod 0755 $(DEB_DESTDIR)$(PREFIX)/sbin/rabbitmqctl for script in rabbitmq-server rabbitmq-plugins; do \ cp -a $(DEB_DESTDIR)$(PREFIX)/sbin/rabbitmqctl \ - $(DEB_DESTDIR)$(PREFIX)/sbin/$$script; \ + $(DEB_DESTDIR)$(PREFIX)/sbin/$$script; \ done + install -p -D -m 0644 debian/rabbitmq-server.default \ + $(DEB_DESTDIR)/etc/default/rabbitmq-server + install -p -D -m 0755 scripts/rabbitmq-server.ocf \ $(DEB_DESTDIR)$(PREFIX)/lib/ocf/resource.d/rabbitmq/rabbitmq-server install -p -D -m 0755 scripts/rabbitmq-server-ha.ocf \ $(DEB_DESTDIR)$(PREFIX)/lib/ocf/resource.d/rabbitmq/rabbitmq-server-ha - # Unlocalify -# mkdir -p $(DEB_DESTDIR)$(PREFIX)/lib/rabbitmq/bin -# mv $(DEB_DESTDIR)$(PREFIX)/local/lib/erlang/bin/* $(DEB_DESTDIR)$(PREFIX)/lib/rabbitmq/bin -# mkdir -p $(DEB_DESTDIR)$(PREFIX)/sbin -# mv $(DEB_DESTDIR)$(PREFIX)/local/lib/erlang/lib/rabbitmq_server-3.6.5/sbin/* $(DEB_DESTDIR)$(PREFIX)/sbin -# rm -rf $(DEB_DESTDIR)$(PREFIX)/local + rm $(DEB_DESTDIR)$(RMQ_ERLAPP_DIR)/LICENSE* \ + $(DEB_DESTDIR)$(RMQ_ERLAPP_DIR)/INSTALL - # Remove extra license files - rm -f $(DEB_DESTDIR)$(PREFIX)/lib/erlang/lib/rabbitmq_server-*/LICENSE - rm -f $(RABBIT_LIB)/LICENSE* $(RABBIT_LIB)/INSTALL* - -override_dh_auto_clean: - rm -f plugins-src/rabbitmq-server plugins/README - #dh_auto_clean + rmdir $(DEB_DESTDIR)$(PREFIX)/lib/erlang/lib \ + $(DEB_DESTDIR)$(PREFIX)/lib/erlang +override_dh_systemd_enable: + dh_systemd_enable --no-enable -override_dh_python2: - dh_python2 --shebang=/usr/bin/python +override_dh_systemd_start: + dh_systemd_start --no-start +override_dh_installinit: + dh_installinit --noscripts diff --git a/debian/source.lintian-overrides b/debian/source.lintian-overrides deleted file mode 100644 index 3d9b7c5..0000000 --- a/debian/source.lintian-overrides +++ /dev/null @@ -1,3 +0,0 @@ -rabbitmq-server source: source-is-missing deps/rabbitmq_management/priv/www/js/help.js line length is 657 characters (>512) -rabbitmq-server source: source-is-missing deps/rabbitmq_management/priv/www/js/jquery.flot.js line length is 2952 characters (>512) -rabbitmq-server source: source-is-missing deps/rabbitmq_shovel_management/priv/www/js/shovel.js line length is 258 characters (>256) diff --git a/debian/watch b/debian/watch index af128d5..b41aff9 100644 --- a/debian/watch +++ b/debian/watch @@ -1,2 +1,4 @@ version=3 -http://www.rabbitmq.com/releases/rabbitmq-server/v(.*)/rabbitmq-server-(\d.*)\.tar\.xz + +http://www.rabbitmq.com/releases/rabbitmq-server/v(.*)/rabbitmq-server-(\d.*)\.tar\.gz \ + debian uupdate diff --git a/rabbitmq-server/deps/amqp_client/CODE_OF_CONDUCT.md b/deps/amqp_client/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/amqp_client/CODE_OF_CONDUCT.md rename to deps/amqp_client/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/amqp_client/CONTRIBUTING.md b/deps/amqp_client/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/amqp_client/CONTRIBUTING.md rename to deps/amqp_client/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/amqp_client/Makefile b/deps/amqp_client/Makefile similarity index 74% rename from rabbitmq-server/deps/amqp_client/Makefile rename to deps/amqp_client/Makefile index 8314d47..8e7399f 100644 --- a/rabbitmq-server/deps/amqp_client/Makefile +++ b/deps/amqp_client/Makefile @@ -1,46 +1,18 @@ PROJECT = amqp_client -PROJECT_DESCRIPTION = RabbitMQ AMQP Client -PROJECT_MOD = amqp_client -PROJECT_REGISTERED = amqp_sup - -define PROJECT_ENV -[ - {prefer_ipv6, false}, - {ssl_options, []} - ] -endef - -define PROJECT_APP_EXTRA_KEYS -%% Hex.pm package informations. - {maintainers, [ - "RabbitMQ Team ", - "Jean-Sebastien Pedron " - ]}, - {licenses, ["MPL 1.1"]}, - {links, [ - {"Website", "http://www.rabbitmq.com/"}, - {"GitHub", "https://github.com/rabbitmq/rabbitmq-erlang-client"}, - {"User guide", "http://www.rabbitmq.com/erlang-client-user-guide.html"} - ]}, - {build_tools, ["make", "rebar3"]}, - {files, [ - $(RABBITMQ_HEXPM_DEFAULT_FILES) - ]} -endef +VERSION ?= $(call get_app_version,src/$(PROJECT).app.src) +ifeq ($(VERSION),) +VERSION = 0.0.0 +endif # Release artifacts are put in $(PACKAGES_DIR). PACKAGES_DIR ?= $(abspath PACKAGES) -LOCAL_DEPS = xmerl DEPS = rabbit_common TEST_DEPS = rabbitmq_ct_helpers rabbit -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-test.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk \ - rabbit_common/mk/rabbitmq-hexpm.mk \ rabbit_common/mk/rabbitmq-dist.mk \ rabbit_common/mk/rabbitmq-run.mk \ - rabbit_common/mk/rabbitmq-test.mk \ rabbit_common/mk/rabbitmq-tools.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be @@ -65,13 +37,13 @@ edoc: doc/overview.edoc doc/overview.edoc: src/overview.edoc.in mkdir -p doc - sed -e 's:%%VERSION%%:$(PROJECT_VERSION):g' < $< > $@ + sed -e 's:%%VERSION%%:$(VERSION):g' < $< > $@ .PHONY: source-dist clean-source-dist SOURCE_DIST_BASE ?= $(PROJECT) SOURCE_DIST_SUFFIXES ?= tar.xz zip -SOURCE_DIST ?= $(PACKAGES_DIR)/$(SOURCE_DIST_BASE)-$(PROJECT_VERSION)-src +SOURCE_DIST ?= $(PACKAGES_DIR)/$(SOURCE_DIST_BASE)-$(VERSION)-src # The first source distribution file is used by packages: if the archive # type changes, you must update all packages' Makefile. @@ -90,27 +62,19 @@ RSYNC_V = $(RSYNC_V_$(V)) RSYNC_FLAGS += -a $(RSYNC_V) \ --exclude '.sw?' --exclude '.*.sw?' \ --exclude '*.beam' \ - --exclude '*.d' \ --exclude '*.pyc' \ --exclude '.git*' \ --exclude '.hg*' \ --exclude '.travis.yml' \ - --exclude '.*.plt' \ --exclude '$(notdir $(ERLANG_MK_TMP))' \ - --exclude 'cover/' \ - --exclude 'deps/' \ - --exclude 'ebin/' \ + --exclude 'ebin' \ --exclude 'erl_crash.dump' \ + --exclude 'deps/' \ --exclude '$(notdir $(DEPS_DIR))/' \ --exclude 'doc/' \ - --exclude 'hexer*' \ - --exclude 'logs/' \ --exclude 'plugins/' \ --exclude '$(notdir $(DIST_DIR))/' \ - --exclude 'test' \ - --exclude 'xrefr' \ --exclude '/$(notdir $(PACKAGES_DIR))/' \ - --exclude '/PACKAGES/' \ --delete \ --delete-excluded @@ -135,8 +99,10 @@ ZIP_V = $(ZIP_V_$(V)) $(SOURCE_DIST): $(ERLANG_MK_RECURSIVE_DEPS_LIST) $(verbose) mkdir -p $(dir $@) $(gen_verbose) $(RSYNC) $(RSYNC_FLAGS) ./ $@/ - $(verbose) echo "$(PROJECT_DESCRIPTION) $(PROJECT_VERSION)" > $@/git-revisions.txt - $(verbose) echo "$(PROJECT) $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)" >> $@/git-revisions.txt + $(verbose) sed -E -i.bak \ + -e 's/[{]vsn[[:blank:]]*,[^}]+}/{vsn, "$(VERSION)"}/' \ + $@/src/$(PROJECT).app.src && \ + rm $@/src/$(PROJECT).app.src.bak $(verbose) for dep in $$(cat $(ERLANG_MK_RECURSIVE_DEPS_LIST) | grep -v '/$(PROJECT)$$' | LC_COLLATE=C sort); do \ $(RSYNC) $(RSYNC_FLAGS) \ $$dep \ @@ -149,17 +115,18 @@ $(SOURCE_DIST): $(ERLANG_MK_RECURSIVE_DEPS_LIST) sed -E -i.bak "s|^[[:blank:]]*include[[:blank:]]+\.\./.*erlang.mk$$|include ../../erlang.mk|" \ $@/deps/$$(basename $$dep)/Makefile && \ rm $@/deps/$$(basename $$dep)/Makefile.bak; \ - (cd $$dep; echo "$$(basename "$$dep") $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)") >> $@/git-revisions.txt; \ done $(verbose) for file in $$(find $@ -name '*.app.src'); do \ - sed -E -i.bak \ - -e 's/[{]vsn[[:blank:]]*,[[:blank:]]*(""|"0.0.0")[[:blank:]]*}/{vsn, "$(PROJECT_VERSION)"}/' \ - $$file; \ + sed -E -i.bak -e 's/[{]vsn[[:blank:]]*,[[:blank:]]*""[[:blank:]]*}/{vsn, "$(VERSION)"}/' $$file; \ rm $$file.bak; \ done + $(verbose) echo "$(PROJECT) $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)" > $@/git-revisions.txt + $(verbose) for dep in $$(cat $(ERLANG_MK_RECURSIVE_DEPS_LIST)); do \ + (cd $$dep; echo "$$(basename "$$dep") $$(git rev-parse HEAD) $$(git describe --tags --exact-match 2>/dev/null || git symbolic-ref -q --short HEAD)") >> $@/git-revisions.txt; \ + done $(verbose) rm $@/README.in $(verbose) cp README.in $@/README - $(verbose) if test "$(BUILD_DOC)"; then cat "$(BUILD_DOC)" >> $@/README; fi + $(verbose) cat "$(BUILD_DOC)" >> $@/README # TODO: Fix file timestamps to have reproducible source archives. # $(verbose) find $@ -not -name 'git-revisions.txt' -print0 | xargs -0 touch -r $@/git-revisions.txt diff --git a/rabbitmq-server/deps/amqp_client/README.in b/deps/amqp_client/README.in similarity index 100% rename from rabbitmq-server/deps/amqp_client/README.in rename to deps/amqp_client/README.in diff --git a/rabbitmq-server/deps/amqp_client/ci/test.sh b/deps/amqp_client/ci/test.sh similarity index 100% rename from rabbitmq-server/deps/amqp_client/ci/test.sh rename to deps/amqp_client/ci/test.sh diff --git a/rabbitmq-server/deps/amqp_client/ci/test.yml b/deps/amqp_client/ci/test.yml similarity index 100% rename from rabbitmq-server/deps/amqp_client/ci/test.yml rename to deps/amqp_client/ci/test.yml diff --git a/rabbitmq-server/deps/ranch/erlang.mk b/deps/amqp_client/erlang.mk similarity index 94% rename from rabbitmq-server/deps/ranch/erlang.mk rename to deps/amqp_client/erlang.mk index 6cecb49..6d2a31c 100644 --- a/rabbitmq-server/deps/ranch/erlang.mk +++ b/deps/amqp_client/erlang.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -12,21 +12,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) -ERLANG_MK_VERSION = 2016.12.08 - -# Make 3.81 and 3.82 are deprecated. - -ifeq ($(MAKE_VERSION),3.81) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif - -ifeq ($(MAKE_VERSION),3.82) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 # Core configuration. @@ -35,7 +25,6 @@ PROJECT := $(strip $(PROJECT)) PROJECT_VERSION ?= rolling PROJECT_MOD ?= $(PROJECT)_app -PROJECT_ENV ?= [] # Verbosity. @@ -96,8 +85,6 @@ all:: deps app rel rel:: $(verbose) : -relup:: deps app - check:: tests clean:: clean-crashdump @@ -115,7 +102,7 @@ distclean-tmp: help:: $(verbose) printf "%s\n" \ "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ - "Copyright (c) 2013-2016 Loïc Hoguin " \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ "" \ "Usage: [V=1] $(MAKE) [target]..." \ "" \ @@ -163,7 +150,30 @@ else core_native_path = $1 endif -core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$1) $2 +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) @@ -276,14 +286,6 @@ pkg_apns_fetch = git pkg_apns_repo = https://github.com/inaka/apns4erl pkg_apns_commit = master -PACKAGES += asciideck -pkg_asciideck_name = asciideck -pkg_asciideck_description = Asciidoc for Erlang. -pkg_asciideck_homepage = https://ninenines.eu -pkg_asciideck_fetch = git -pkg_asciideck_repo = https://github.com/ninenines/asciideck -pkg_asciideck_commit = master - PACKAGES += azdht pkg_azdht_name = azdht pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang @@ -404,14 +406,6 @@ pkg_bootstrap_fetch = git pkg_bootstrap_repo = https://github.com/schlagert/bootstrap pkg_bootstrap_commit = master -PACKAGES += boss -pkg_boss_name = boss -pkg_boss_description = Erlang web MVC, now featuring Comet -pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_fetch = git -pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_commit = master - PACKAGES += boss_db pkg_boss_db_name = boss_db pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang @@ -420,6 +414,14 @@ pkg_boss_db_fetch = git pkg_boss_db_repo = https://github.com/ErlyORM/boss_db pkg_boss_db_commit = master +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + PACKAGES += brod pkg_brod_name = brod pkg_brod_description = Kafka client in Erlang @@ -564,13 +566,13 @@ pkg_cloudi_service_api_requests_fetch = git pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests pkg_cloudi_service_api_requests_commit = master -PACKAGES += cloudi_service_db -pkg_cloudi_service_db_name = cloudi_service_db -pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) -pkg_cloudi_service_db_homepage = http://cloudi.org/ -pkg_cloudi_service_db_fetch = git -pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db -pkg_cloudi_service_db_commit = master +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master PACKAGES += cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra @@ -580,14 +582,6 @@ pkg_cloudi_service_db_cassandra_fetch = git pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_commit = master -PACKAGES += cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service -pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ -pkg_cloudi_service_db_cassandra_cql_fetch = git -pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_commit = master - PACKAGES += cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service @@ -644,6 +638,14 @@ pkg_cloudi_service_db_tokyotyrant_fetch = git pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_commit = master +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + PACKAGES += cloudi_service_filesystem pkg_cloudi_service_filesystem_name = cloudi_service_filesystem pkg_cloudi_service_filesystem_description = Filesystem CloudI Service @@ -1036,14 +1038,6 @@ pkg_edown_fetch = git pkg_edown_repo = https://github.com/uwiger/edown pkg_edown_commit = master -PACKAGES += eep -pkg_eep_name = eep -pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy -pkg_eep_homepage = https://github.com/virtan/eep -pkg_eep_fetch = git -pkg_eep_repo = https://github.com/virtan/eep -pkg_eep_commit = master - PACKAGES += eep_app pkg_eep_app_name = eep_app pkg_eep_app_description = Embedded Event Processing @@ -1052,6 +1046,14 @@ pkg_eep_app_fetch = git pkg_eep_app_repo = https://github.com/darach/eep-erl pkg_eep_app_commit = master +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + PACKAGES += efene pkg_efene_name = efene pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX @@ -1236,14 +1238,6 @@ pkg_eqm_fetch = git pkg_eqm_repo = https://github.com/loucash/eqm pkg_eqm_commit = master -PACKAGES += eredis -pkg_eredis_name = eredis -pkg_eredis_description = Erlang Redis client -pkg_eredis_homepage = https://github.com/wooga/eredis -pkg_eredis_fetch = git -pkg_eredis_repo = https://github.com/wooga/eredis -pkg_eredis_commit = master - PACKAGES += eredis_pool pkg_eredis_pool_name = eredis_pool pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. @@ -1252,6 +1246,14 @@ pkg_eredis_pool_fetch = git pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_commit = master +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + PACKAGES += erl_streams pkg_erl_streams_name = erl_streams pkg_erl_streams_description = Streams in Erlang @@ -1540,14 +1542,6 @@ pkg_etap_fetch = git pkg_etap_repo = https://github.com/ngerakines/etap pkg_etap_commit = master -PACKAGES += etest -pkg_etest_name = etest -pkg_etest_description = A lightweight, convention over configuration test framework for Erlang -pkg_etest_homepage = https://github.com/wooga/etest -pkg_etest_fetch = git -pkg_etest_repo = https://github.com/wooga/etest -pkg_etest_commit = master - PACKAGES += etest_http pkg_etest_http_name = etest_http pkg_etest_http_description = etest Assertions around HTTP (client-side) @@ -1556,6 +1550,14 @@ pkg_etest_http_fetch = git pkg_etest_http_repo = https://github.com/wooga/etest_http pkg_etest_http_commit = master +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + PACKAGES += etoml pkg_etoml_name = etoml pkg_etoml_description = TOML language erlang parser @@ -1564,14 +1566,6 @@ pkg_etoml_fetch = git pkg_etoml_repo = https://github.com/kalta/etoml pkg_etoml_commit = master -PACKAGES += eunit -pkg_eunit_name = eunit -pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. -pkg_eunit_homepage = https://github.com/richcarl/eunit -pkg_eunit_fetch = git -pkg_eunit_repo = https://github.com/richcarl/eunit -pkg_eunit_commit = master - PACKAGES += eunit_formatters pkg_eunit_formatters_name = eunit_formatters pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. @@ -1580,6 +1574,14 @@ pkg_eunit_formatters_fetch = git pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_commit = master +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + PACKAGES += euthanasia pkg_euthanasia_name = euthanasia pkg_euthanasia_description = Merciful killer for your Erlang processes @@ -1597,7 +1599,7 @@ pkg_evum_repo = https://github.com/msantos/evum pkg_evum_commit = master PACKAGES += exec -pkg_exec_name = erlexec +pkg_exec_name = exec pkg_exec_description = Execute and control OS processes from Erlang/OTP. pkg_exec_homepage = http://saleyn.github.com/erlexec pkg_exec_fetch = git @@ -1716,14 +1718,6 @@ pkg_fn_fetch = git pkg_fn_repo = https://github.com/reiddraper/fn pkg_fn_commit = master -PACKAGES += folsom -pkg_folsom_name = folsom -pkg_folsom_description = Expose Erlang Events and Metrics -pkg_folsom_homepage = https://github.com/boundary/folsom -pkg_folsom_fetch = git -pkg_folsom_repo = https://github.com/boundary/folsom -pkg_folsom_commit = master - PACKAGES += folsom_cowboy pkg_folsom_cowboy_name = folsom_cowboy pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. @@ -1732,6 +1726,14 @@ pkg_folsom_cowboy_fetch = git pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_commit = master +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + PACKAGES += folsomite pkg_folsomite_name = folsomite pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics @@ -2092,14 +2094,6 @@ pkg_jesse_fetch = git pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master -PACKAGES += jiffy -pkg_jiffy_name = jiffy -pkg_jiffy_description = JSON NIFs for Erlang. -pkg_jiffy_homepage = https://github.com/davisp/jiffy -pkg_jiffy_fetch = git -pkg_jiffy_repo = https://github.com/davisp/jiffy -pkg_jiffy_commit = master - PACKAGES += jiffy_v pkg_jiffy_v_name = jiffy_v pkg_jiffy_v_description = JSON validation utility @@ -2108,6 +2102,14 @@ pkg_jiffy_v_fetch = git pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v pkg_jiffy_v_commit = master +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + PACKAGES += jobs pkg_jobs_name = jobs pkg_jobs_description = a Job scheduler for load regulation @@ -2124,14 +2126,6 @@ pkg_joxa_fetch = git pkg_joxa_repo = https://github.com/joxa/joxa pkg_joxa_commit = master -PACKAGES += json -pkg_json_name = json -pkg_json_description = a high level json library for erlang (17.0+) -pkg_json_homepage = https://github.com/talentdeficit/json -pkg_json_fetch = git -pkg_json_repo = https://github.com/talentdeficit/json -pkg_json_commit = master - PACKAGES += json_rec pkg_json_rec_name = json_rec pkg_json_rec_description = JSON to erlang record @@ -2140,6 +2134,14 @@ pkg_json_rec_fetch = git pkg_json_rec_repo = https://github.com/justinkirby/json_rec pkg_json_rec_commit = master +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + PACKAGES += jsone pkg_jsone_name = jsone pkg_jsone_description = An Erlang library for encoding, decoding JSON data. @@ -2180,14 +2182,6 @@ pkg_jsx_fetch = git pkg_jsx_repo = https://github.com/talentdeficit/jsx pkg_jsx_commit = master -PACKAGES += kafka -pkg_kafka_name = kafka -pkg_kafka_description = Kafka consumer and producer in Erlang -pkg_kafka_homepage = https://github.com/wooga/kafka-erlang -pkg_kafka_fetch = git -pkg_kafka_repo = https://github.com/wooga/kafka-erlang -pkg_kafka_commit = master - PACKAGES += kafka_protocol pkg_kafka_protocol_name = kafka_protocol pkg_kafka_protocol_description = Kafka protocol Erlang library @@ -2196,6 +2190,14 @@ pkg_kafka_protocol_fetch = git pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git pkg_kafka_protocol_commit = master +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + PACKAGES += kai pkg_kai_name = kai pkg_kai_description = DHT storage by Takeshi Inoue @@ -2292,14 +2294,6 @@ pkg_kvs_fetch = git pkg_kvs_repo = https://github.com/synrc/kvs pkg_kvs_commit = master -PACKAGES += lager -pkg_lager_name = lager -pkg_lager_description = A logging framework for Erlang/OTP. -pkg_lager_homepage = https://github.com/basho/lager -pkg_lager_fetch = git -pkg_lager_repo = https://github.com/basho/lager -pkg_lager_commit = master - PACKAGES += lager_amqp_backend pkg_lager_amqp_backend_name = lager_amqp_backend pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend @@ -2316,6 +2310,14 @@ pkg_lager_syslog_fetch = git pkg_lager_syslog_repo = https://github.com/basho/lager_syslog pkg_lager_syslog_commit = master +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + PACKAGES += lambdapad pkg_lambdapad_name = lambdapad pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. @@ -2572,14 +2574,6 @@ pkg_mixer_fetch = git pkg_mixer_repo = https://github.com/chef/mixer pkg_mixer_commit = master -PACKAGES += mochiweb -pkg_mochiweb_name = mochiweb -pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. -pkg_mochiweb_homepage = https://github.com/mochi/mochiweb -pkg_mochiweb_fetch = git -pkg_mochiweb_repo = https://github.com/mochi/mochiweb -pkg_mochiweb_commit = master - PACKAGES += mochiweb_xpath pkg_mochiweb_xpath_name = mochiweb_xpath pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser @@ -2588,6 +2582,14 @@ pkg_mochiweb_xpath_fetch = git pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_commit = master +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + PACKAGES += mockgyver pkg_mockgyver_name = mockgyver pkg_mockgyver_description = A mocking library for Erlang @@ -3060,14 +3062,6 @@ pkg_quickrand_fetch = git pkg_quickrand_repo = https://github.com/okeuday/quickrand pkg_quickrand_commit = master -PACKAGES += rabbit -pkg_rabbit_name = rabbit -pkg_rabbit_description = RabbitMQ Server -pkg_rabbit_homepage = https://www.rabbitmq.com/ -pkg_rabbit_fetch = git -pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git -pkg_rabbit_commit = master - PACKAGES += rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak @@ -3076,6 +3070,14 @@ pkg_rabbit_exchange_type_riak_fetch = git pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_commit = master +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + PACKAGES += rack pkg_rack_name = rack pkg_rack_description = Rack handler for erlang @@ -3492,14 +3494,6 @@ pkg_smother_fetch = git pkg_smother_repo = https://github.com/ramsay-t/Smother pkg_smother_commit = master -PACKAGES += snappyer -pkg_snappyer_name = snappyer -pkg_snappyer_description = Snappy as nif for Erlang -pkg_snappyer_homepage = https://github.com/zmstone/snappyer -pkg_snappyer_fetch = git -pkg_snappyer_repo = https://github.com/zmstone/snappyer.git -pkg_snappyer_commit = master - PACKAGES += social pkg_social_name = social pkg_social_description = Cowboy handler for social login via OAuth2 providers @@ -3548,14 +3542,6 @@ pkg_stable_fetch = git pkg_stable_repo = https://github.com/dvv/stable pkg_stable_commit = master -PACKAGES += statebox -pkg_statebox_name = statebox -pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. -pkg_statebox_homepage = https://github.com/mochi/statebox -pkg_statebox_fetch = git -pkg_statebox_repo = https://github.com/mochi/statebox -pkg_statebox_commit = master - PACKAGES += statebox_riak pkg_statebox_riak_name = statebox_riak pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. @@ -3564,6 +3550,14 @@ pkg_statebox_riak_fetch = git pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak pkg_statebox_riak_commit = master +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + PACKAGES += statman pkg_statman_name = statman pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM @@ -4068,7 +4062,7 @@ pkg_zucchini_fetch = git pkg_zucchini_repo = https://github.com/devinus/zucchini pkg_zucchini_commit = master -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: search @@ -4095,7 +4089,7 @@ else $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-deps @@ -4172,9 +4166,6 @@ endif ifneq ($(SKIP_DEPS),) deps:: else -ifeq ($(ALL_DEPS_DIRS),) -deps:: apps -else deps:: $(ALL_DEPS_DIRS) apps ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log @@ -4194,7 +4185,6 @@ endif fi \ done endif -endif # Deps related targets. @@ -4203,16 +4193,17 @@ endif # in practice only Makefile is needed so far. define dep_autopatch if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ - rm -rf $(DEPS_DIR)/$1/ebin/; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ $(call dep_autopatch_erlang_mk,$(1)); \ elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ @@ -4224,8 +4215,6 @@ define dep_autopatch endef define dep_autopatch2 - mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ - rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ fi; \ @@ -4265,7 +4254,7 @@ define dep_autopatch_fetch_rebar if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ - git checkout -q 576e12171ab8d69b048b827b92aa65d067deea01; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ $(MAKE); \ cd -; \ fi @@ -4282,7 +4271,6 @@ endef define dep_autopatch_rebar.erl application:load(rebar), application:set_env(rebar, log_level, debug), - rmemo:start(), Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of {ok, Conf0} -> Conf0; _ -> [] @@ -4436,9 +4424,9 @@ define dep_autopatch_rebar.erl [] -> ok; _ -> Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), - PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -4477,7 +4465,7 @@ define dep_autopatch_rebar.erl "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", - [[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], Output, ": $$\(foreach ext,.c .C .cc .cpp,", "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", @@ -4537,6 +4525,22 @@ define dep_autopatch_rebar.erl halt() endef +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", @@ -4584,12 +4588,21 @@ define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex - mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ - $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ - https://s3.amazonaws.com/s3.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ - tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); endef define dep_fetch_fail @@ -4704,7 +4717,7 @@ $(foreach p,$(DEP_PLUGINS),\ $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ $(call core_dep_plugin,$p/plugins.mk,$p)))) -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Configuration. @@ -4721,14 +4734,15 @@ dtl_verbose = $(dtl_verbose_$(V)) # Core targets. -DTL_PATH := $(abspath $(DTL_PATH)) -DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) ifneq ($(DTL_FILES),) -DTL_NAMES = $(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)) -DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) -BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif ifneq ($(words $(DTL_FILES)),0) # Rebuild templates when the Makefile changes. @@ -4748,11 +4762,11 @@ define erlydtl_compile.erl "" -> filename:basename(F, ".dtl"); _ -> - "$(DTL_PATH)/" ++ F2 = filename:rootname(F, ".dtl"), + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), re:replace(F2, "/", "_", [{return, list}, global]) end, Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), - case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of ok -> ok; {ok, _} -> ok end @@ -4762,12 +4776,11 @@ endef ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ - -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Verbosity. @@ -4799,7 +4812,7 @@ ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) $(if $(strip $?),$(call compile_proto,$?)) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app @@ -4868,8 +4881,7 @@ define app_file {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} ]}. endef else @@ -4881,8 +4893,7 @@ define app_file {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {mod, {$(PROJECT_MOD), []}}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {mod, {$(PROJECT_MOD), []}} ]}. endef endif @@ -4892,10 +4903,8 @@ app-build: ebin/$(PROJECT).app # Source files. -ALL_SRC_FILES := $(sort $(call core_find,src/,*)) - -ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES)) -CORE_FILES := $(filter %.core,$(ALL_SRC_FILES)) +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) # ASN.1 files. @@ -4928,16 +4937,16 @@ endif # Leex and Yecc files. -XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES)) +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) ERL_FILES += $(XRL_ERL_FILES) -YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES)) +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) ERL_FILES += $(YRL_ERL_FILES) $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) - $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) # Erlang and Core Erlang files. @@ -5026,12 +5035,12 @@ endif ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) if test -f $@; then \ + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ fi - $(verbose) touch $@ + @touch $@ $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change @@ -5056,7 +5065,7 @@ ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.s $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) - $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ > ebin/$(PROJECT).app else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ @@ -5080,7 +5089,6 @@ clean-app: endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5101,7 +5109,7 @@ doc-deps: $(ALL_DOC_DEPS_DIRS) $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rel-deps @@ -5121,7 +5129,7 @@ rel-deps: $(ALL_REL_DEPS_DIRS) $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: test-deps test-dir test-build clean-test-dir @@ -5176,7 +5184,7 @@ ifneq ($(wildcard $(TEST_DIR)/*.beam),) endif endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rebar.config @@ -5212,90 +5220,54 @@ $(eval export _compat_rebar_config) rebar.config: $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck) +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc -.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual - -# Core targets. +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 docs:: asciidoc -distclean:: distclean-asciidoc-guide distclean-asciidoc-manual - -# Plugin-specific targets. - asciidoc: asciidoc-guide asciidoc-manual -# User guide. - ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else -asciidoc-guide: distclean-asciidoc-guide doc-deps +asciidoc-guide: distclean-asciidoc doc-deps a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ - -distclean-asciidoc-guide: - $(gen_verbose) rm -rf doc/html/ doc/guide.pdf endif -# Man pages. - -ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc) - -ifeq ($(ASCIIDOC_MANUAL_FILES),) +ifeq ($(wildcard doc/src/manual/*.asciidoc),) asciidoc-manual: else - -# Configuration. - -MAN_INSTALL_PATH ?= /usr/local/share/man -MAN_SECTIONS ?= 3 7 -MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/') -MAN_VERSION ?= $(PROJECT_VERSION) - -# Plugin-specific targets. - -define asciidoc2man.erl -try - [begin - io:format(" ADOC ~s~n", [F]), - ok = asciideck:to_manpage(asciideck:parse_file(F), #{ - compress => gzip, - outdir => filename:dirname(F), - extra2 => "$(MAN_PROJECT) $(MAN_VERSION)", - extra3 => "$(MAN_PROJECT) Function Reference" - }) - end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]], - halt(0) -catch C:E -> - io:format("Exception ~p:~p~nStacktrace: ~p~n", [C, E, erlang:get_stacktrace()]), - halt(1) -end. -endef - -asciidoc-manual:: doc-deps - -asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) - $(call erlang,$(call asciidoc2man.erl,$?)) - $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done install-docs:: install-asciidoc install-asciidoc: asciidoc-manual - $(foreach s,$(MAN_SECTIONS),\ - mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ - install -g `id -u` -o `id -g` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) - -distclean-asciidoc-manual: - $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) -endif + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done endif -# Copyright (c) 2014-2016, Loïc Hoguin +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates @@ -5352,7 +5324,7 @@ ifdef SP define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 # Whitespace to be used when creating files from templates. SP = $(SP) @@ -5362,7 +5334,7 @@ else define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 endef endif @@ -5370,7 +5342,7 @@ endif define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk endef @@ -5390,7 +5362,7 @@ stop(_State) -> endef define bs_relx_config -{release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. +{release, {$p_release, "1"}, [$p]}. {extended_start_script, true}. {sys_config, "rel/sys.config"}. {vm_args, "rel/vm.args"}. @@ -5756,7 +5728,7 @@ endif list-templates: $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) -# Copyright (c) 2014-2016, Loïc Hoguin +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-c_src distclean-c_src-env @@ -5991,94 +5963,56 @@ else $(call render_template,bs_erl_nif,src/$n.erl) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ci ci-prepare ci-setup distclean-kerl - -CI_OTP ?= -CI_HIPE ?= -CI_ERLLVM ?= - -ifeq ($(CI_VM),native) -ERLC_OPTS += +native -TEST_ERLC_OPTS += +native -else ifeq ($(CI_VM),erllvm) -ERLC_OPTS += +native +'{hipe, [to_llvm]}' -TEST_ERLC_OPTS += +native +'{hipe, [to_llvm]}' -endif - -ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) -ci:: -else - -ifeq ($(strip $(KERL)),) -KERL := $(ERLANG_MK_TMP)/kerl/kerl -endif +.PHONY: ci ci-setup distclean-kerl +KERL ?= $(CURDIR)/kerl export KERL -KERL_GIT ?= https://github.com/kerl/kerl -KERL_COMMIT ?= master - -KERL_MAKEFLAGS ?= +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl OTP_GIT ?= https://github.com/erlang/otp CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= -ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) -ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) ci-setup:: -ci-extra:: - ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target -ci-$1: $(CI_INSTALL_DIR)/$2 - $(verbose) $(MAKE) --no-print-directory clean +ci-$(1): $(CI_INSTALL_DIR)/$(1) $(ci_verbose) \ - PATH="$(CI_INSTALL_DIR)/$2/bin:$(PATH)" \ - CI_OTP_RELEASE="$1" \ - CT_OPTS="-label $1" \ - CI_VM="$3" \ - $(MAKE) ci-setup tests - $(verbose) $(MAKE) --no-print-directory ci-extra + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests endef -$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) -$(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) -$(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) define ci_otp_target ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) $(CI_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) build git $(OTP_GIT) $(1) $(1) $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) endif endef $(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) -define ci_hipe_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$1-native),) -$(CI_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(CI_INSTALL_DIR)/$1-native -endif -endef - -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call ci_hipe_target,$(otp)))) - $(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl - $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) $(verbose) chmod +x $(KERL) help:: @@ -6095,7 +6029,7 @@ distclean-kerl: $(gen_verbose) rm -rf $(KERL) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ct apps-ct distclean-ct @@ -6103,14 +6037,11 @@ endif # Configuration. CT_OPTS ?= - ifneq ($(wildcard $(TEST_DIR)),) -ifndef CT_SUITES -CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) -endif + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= endif -CT_SUITES ?= -CT_LOGS_DIR ?= $(CURDIR)/logs # Core targets. @@ -6133,13 +6064,13 @@ CT_RUN = ct_run \ -noinput \ -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ - -logdir $(CT_LOGS_DIR) + -logdir $(CURDIR)/logs ifeq ($(CT_SUITES),) ct: $(if $(IS_APP),,apps-ct) else ct: test-build $(if $(IS_APP),,apps-ct) - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif @@ -6167,16 +6098,16 @@ endif define ct_suite_target ct-$(1): test-build - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) distclean-ct: - $(gen_verbose) rm -rf $(CT_LOGS_DIR) + $(gen_verbose) rm -rf $(CURDIR)/logs/ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: plt distclean-plt dialyze @@ -6220,10 +6151,7 @@ define filter_opts.erl endef $(DIALYZER_PLT): deps app - $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ - while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) - $(verbose) dialyzer --build_plt --apps erts kernel stdlib \ - $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) plt: $(DIALYZER_PLT) @@ -6237,7 +6165,7 @@ dialyze: $(DIALYZER_PLT) endif $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-edoc edoc @@ -6262,23 +6190,25 @@ edoc: distclean-edoc doc-deps distclean-edoc: $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2014, Dave Cottlehuber +# Copyright (c) 2014 Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-escript escript escript-zip +.PHONY: distclean-escript escript # Configuration. ESCRIPT_NAME ?= $(PROJECT) ESCRIPT_FILE ?= $(ESCRIPT_NAME) -ESCRIPT_SHEBANG ?= /usr/bin/env escript ESCRIPT_COMMENT ?= This is an -*- erlang -*- file -ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME) -ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null) -ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" # Core targets. @@ -6291,28 +6221,44 @@ help:: # Plugin-specific targets. -escript-zip:: deps app - $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) - $(verbose) rm -f $(ESCRIPT_ZIP_FILE) - $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* -ifneq ($(DEPS),) - $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ - `cat $(ERLANG_MK_TMP)/deps.log | sed 's/^$(subst /,\/,$(DEPS_DIR))\///' | sed 's/$$/\/ebin\/\*/'` -endif +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef -escript:: escript-zip - $(gen_verbose) printf "%s\n" \ - "#!$(ESCRIPT_SHEBANG)" \ - "%% $(ESCRIPT_COMMENT)" \ - "%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE) - $(verbose) cat $(ESCRIPT_ZIP_FILE) >> $(ESCRIPT_FILE) - $(verbose) chmod +x $(ESCRIPT_FILE) +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) distclean-escript: $(gen_verbose) rm -f $(ESCRIPT_NAME) -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: eunit apps-eunit @@ -6380,14 +6326,14 @@ apps-eunit: endif endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: relx-rel relx-relup distclean-relx-rel run +.PHONY: relx-rel distclean-relx-rel distclean-relx run # Configuration. -RELX ?= $(ERLANG_MK_TMP)/relx +RELX ?= $(CURDIR)/relx RELX_CONFIG ?= $(CURDIR)/relx.config RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx @@ -6405,12 +6351,10 @@ endif ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) rel:: relx-rel - -relup:: relx-relup endif endif -distclean:: distclean-relx-rel +distclean:: distclean-relx-rel distclean-relx # Plugin-specific targets. @@ -6419,14 +6363,14 @@ $(RELX): $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release tar - -relx-relup: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release relup tar + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) @@ -6435,17 +6379,15 @@ else define get_relx_release.erl {ok, Config} = file:consult("$(RELX_CONFIG)"), - {release, {Name, Vsn}, _} = lists:keyfind(release, 1, Config), - io:format("~s ~s", [Name, Vsn]), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), halt(0). endef -RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) -RELX_REL_NAME := $(word 1,$(RELX_REL)) -RELX_REL_VSN := $(word 2,$(RELX_REL)) +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` run: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME) console + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console help:: $(verbose) printf "%s\n" "" \ @@ -6454,8 +6396,8 @@ help:: endif -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: shell @@ -6485,7 +6427,7 @@ build-shell-deps: $(ALL_SHELL_DEPS_DIRS) shell: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) @@ -6496,7 +6438,7 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl - code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), try case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); @@ -6528,7 +6470,6 @@ triq: test-build endif endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Erlang Solutions Ltd. # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6568,8 +6509,7 @@ xref: deps app $(XREFR) distclean-xref: $(gen_verbose) rm -rf $(XREFR) -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2015, Viktor Söderqvist +# Copyright 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR = cover @@ -6691,53 +6631,6 @@ cover-report: endif endif # ifneq ($(COVER_REPORT_DIR),) -# Copyright (c) 2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -.PHONY: sfx - -ifdef RELX_REL -ifdef SFX - -# Configuration. - -SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz -SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run - -# Core targets. - -rel:: sfx - -# Plugin-specific targets. - -define sfx_stub -#!/bin/sh - -TMPDIR=`mktemp -d` -ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0` -FILENAME=$$(basename $$0) -REL=$${FILENAME%.*} - -tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR - -$$TMPDIR/bin/$$REL console -RET=$$? - -rm -rf $$TMPDIR - -exit $$RET - -__ARCHIVE_BELOW__ -endef - -sfx: - $(call render_template,sfx_stub,$(SFX_OUTPUT_FILE)) - $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) - $(verbose) chmod +x $(SFX_OUTPUT_FILE) - -endif -endif - # Copyright (c) 2013-2015, Loïc Hoguin # Copyright (c) 2015-2016, Jean-Sébastien Pédron # This file is part of erlang.mk and subject to the terms of the ISC License. diff --git a/rabbitmq-server/deps/amqp_client/include/amqp_client.hrl b/deps/amqp_client/include/amqp_client.hrl similarity index 100% rename from rabbitmq-server/deps/amqp_client/include/amqp_client.hrl rename to deps/amqp_client/include/amqp_client.hrl diff --git a/rabbitmq-server/deps/amqp_client/include/amqp_client_internal.hrl b/deps/amqp_client/include/amqp_client_internal.hrl similarity index 100% rename from rabbitmq-server/deps/amqp_client/include/amqp_client_internal.hrl rename to deps/amqp_client/include/amqp_client_internal.hrl diff --git a/rabbitmq-server/deps/amqp_client/include/amqp_gen_consumer_spec.hrl b/deps/amqp_client/include/amqp_gen_consumer_spec.hrl similarity index 100% rename from rabbitmq-server/deps/amqp_client/include/amqp_gen_consumer_spec.hrl rename to deps/amqp_client/include/amqp_gen_consumer_spec.hrl diff --git a/rabbitmq-server/deps/amqp_client/include/rabbit_routing_prefixes.hrl b/deps/amqp_client/include/rabbit_routing_prefixes.hrl similarity index 100% rename from rabbitmq-server/deps/amqp_client/include/rabbit_routing_prefixes.hrl rename to deps/amqp_client/include/rabbit_routing_prefixes.hrl diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/rabbitmq-components.mk b/deps/amqp_client/rabbitmq-components.mk similarity index 83% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/rabbitmq-components.mk rename to deps/amqp_client/rabbitmq-components.mk index 1e5d000..05986d8 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/rabbitmq-components.mk +++ b/deps/amqp_client/rabbitmq-components.mk @@ -5,27 +5,6 @@ ifeq ($(.DEFAULT_GOAL),) .DEFAULT_GOAL = all endif -# PROJECT_VERSION defaults to: -# 1. the version exported by rabbitmq-server-release; -# 2. the version stored in `git-revisions.txt`, if it exists; -# 3. a version based on git-describe(1), if it is a Git clone; -# 4. 0.0.0 - -PROJECT_VERSION := $(RABBITMQ_VERSION) - -ifeq ($(PROJECT_VERSION),) -PROJECT_VERSION := $(shell \ -if test -f git-revisions.txt; then \ - head -n1 git-revisions.txt | \ - awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ -else \ - (git describe --dirty --abbrev=7 --tags --always --first-parent \ - 2>/dev/null || echo rabbitmq_v0_0_0) | \ - sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ - -e 's/-/./g'; \ -fi) -endif - # -------------------------------------------------------------------- # RabbitMQ components. # -------------------------------------------------------------------- @@ -42,17 +21,13 @@ dep_rabbit = git_rmq rabbitmq-server $(current_rmq_re dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master @@ -61,7 +36,6 @@ dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rm dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master @@ -73,11 +47,6 @@ dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(cur dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master @@ -97,41 +66,30 @@ dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(cu dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master -# Third-party dependencies version pinning. -# -# We do that in this file, which is copied in all projects, to ensure -# all projects use the same versions. It avoids conflicts and makes it -# possible to work with rabbitmq-public-umbrella. - -dep_cowboy_commit = 1.0.4 -dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2 -# Last commit of PropEr supporting Erlang R16B03. -dep_proper_commit = 735d972758d8bd85b12483626fe1b66450d6a6fe -dep_ranch_commit = 1.3.2 -# Last commit of sockjs support Erlang R16B03 and 17.x. -dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 5af2b588c812c318b19bc105b577a759c71c3e0a -dep_webmachine_commit = 1.10.8p2 +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 RABBITMQ_COMPONENTS = amqp_client \ rabbit \ rabbit_common \ rabbitmq_amqp1_0 \ rabbitmq_auth_backend_amqp \ - rabbitmq_auth_backend_cache \ rabbitmq_auth_backend_http \ rabbitmq_auth_backend_ldap \ rabbitmq_auth_mechanism_ssl \ - rabbitmq_aws \ rabbitmq_boot_steps_visualiser \ rabbitmq_clusterer \ - rabbitmq_cli \ rabbitmq_codegen \ rabbitmq_consistent_hash_exchange \ - rabbitmq_ct_client_helpers \ rabbitmq_ct_helpers \ rabbitmq_delayed_message_exchange \ rabbitmq_dotnet_client \ @@ -140,7 +98,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_federation_management \ rabbitmq_java_client \ rabbitmq_jms_client \ - rabbitmq_jms_cts \ rabbitmq_jms_topic_exchange \ rabbitmq_lvc \ rabbitmq_management \ @@ -152,11 +109,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_metronome \ rabbitmq_mqtt \ rabbitmq_objc_client \ - rabbitmq_peer_discovery_aws \ - rabbitmq_peer_discovery_common \ - rabbitmq_peer_discovery_consul \ - rabbitmq_peer_discovery_etcd \ - rabbitmq_peer_discovery_k8s \ rabbitmq_recent_history_exchange \ rabbitmq_routing_node_stamp \ rabbitmq_rtopic_exchange \ diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_auth_mechanisms.erl b/deps/amqp_client/src/amqp_auth_mechanisms.erl similarity index 96% rename from rabbitmq-server/deps/amqp_client/src/amqp_auth_mechanisms.erl rename to deps/amqp_client/src/amqp_auth_mechanisms.erl index f4f488b..5517811 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_auth_mechanisms.erl +++ b/deps/amqp_client/src/amqp_auth_mechanisms.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_channel.erl b/deps/amqp_client/src/amqp_channel.erl similarity index 96% rename from rabbitmq-server/deps/amqp_client/src/amqp_channel.erl rename to deps/amqp_client/src/amqp_channel.erl index e550ead..fd1e631 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_channel.erl +++ b/deps/amqp_client/src/amqp_channel.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @type close_reason(Type) = {shutdown, amqp_reason(Type)}. @@ -103,7 +103,7 @@ %% true | false, only relevant in the direct %% client case. %% when true, consumers will manually notify - %% queue pids using rabbit_amqqueue_common:notify_sent/2 + %% queue pids using rabbit_amqqueue:notify_sent/2 %% to prevent the queue from overwhelming slow %% consumers that use automatic acknowledgement %% mode. @@ -425,7 +425,7 @@ handle_cast(enable_delivery_flow_control, State) -> {noreply, State#state{delivery_flow_control = true}}; %% @private handle_cast({send_notify, {QPid, ChPid}}, State) -> - rabbit_amqqueue_common:notify_sent(QPid, ChPid), + rabbit_amqqueue:notify_sent(QPid, ChPid), {noreply, State}; %% @private handle_cast({cast, Method, AmqpMsg, Sender, noflow}, State) -> @@ -489,7 +489,7 @@ handle_info({send_command_and_notify, QPid, ChPid, State = #state{delivery_flow_control = MFC}) -> case MFC of false -> handle_method_from_server(Method, Content, State), - rabbit_amqqueue_common:notify_sent(QPid, ChPid); + rabbit_amqqueue:notify_sent(QPid, ChPid); true -> handle_method_from_server(Method, Content, {self(), QPid, ChPid}, State) end, @@ -500,7 +500,7 @@ handle_info({channel_exit, _ChNumber, Reason}, State) -> handle_channel_exit(Reason, State); %% This comes from rabbit_channel in the direct case handle_info({channel_closing, ChPid}, State) -> - ok = rabbit_channel_common:ready_for_close(ChPid), + ok = rabbit_channel:ready_for_close(ChPid), {noreply, State}; %% @private handle_info({bump_credit, Msg}, State) -> @@ -512,34 +512,25 @@ handle_info(timed_out_flushing_channel, State) -> "connection closing~n", [self()]), {stop, timed_out_flushing_channel, State}; %% @private -handle_info({'DOWN', _, process, ReturnHandler, shutdown}, - State = #state{return_handler = {ReturnHandler, _Ref}}) -> - {noreply, State#state{return_handler = none}}; handle_info({'DOWN', _, process, ReturnHandler, Reason}, State = #state{return_handler = {ReturnHandler, _Ref}}) -> ?LOG_WARN("Channel (~p): Unregistering return handler ~p because it died. " "Reason: ~p~n", [self(), ReturnHandler, Reason]), {noreply, State#state{return_handler = none}}; %% @private -handle_info({'DOWN', _, process, ConfirmHandler, shutdown}, - State = #state{confirm_handler = {ConfirmHandler, _Ref}}) -> - {noreply, State#state{confirm_handler = none}}; handle_info({'DOWN', _, process, ConfirmHandler, Reason}, State = #state{confirm_handler = {ConfirmHandler, _Ref}}) -> ?LOG_WARN("Channel (~p): Unregistering confirm handler ~p because it died. " "Reason: ~p~n", [self(), ConfirmHandler, Reason]), {noreply, State#state{confirm_handler = none}}; %% @private -handle_info({'DOWN', _, process, FlowHandler, shutdown}, - State = #state{flow_handler = {FlowHandler, _Ref}}) -> - {noreply, State#state{flow_handler = none}}; handle_info({'DOWN', _, process, FlowHandler, Reason}, State = #state{flow_handler = {FlowHandler, _Ref}}) -> ?LOG_WARN("Channel (~p): Unregistering flow handler ~p because it died. " "Reason: ~p~n", [self(), FlowHandler, Reason]), {noreply, State#state{flow_handler = none}}; handle_info({'DOWN', _, process, QPid, _Reason}, State) -> - rabbit_amqqueue_common:notify_sent_queue_down(QPid), + rabbit_amqqueue:notify_sent_queue_down(QPid), {noreply, State}; handle_info({confirm_timeout, From}, State = #state{waiting_set = WSet}) -> case gb_trees:lookup(From, WSet) of @@ -864,9 +855,9 @@ do(Method, Content, Flow, #state{driver = network, writer = W}) -> do(Method, Content, Flow, #state{driver = direct, writer = W}) -> %% ditto catching because... catch case {Content, Flow} of - {none, _} -> rabbit_channel_common:do(W, Method); - {_, flow} -> rabbit_channel_common:do_flow(W, Method, Content); - {_, noflow} -> rabbit_channel_common:do(W, Method, Content) + {none, _} -> rabbit_channel:do(W, Method); + {_, flow} -> rabbit_channel:do_flow(W, Method, Content); + {_, noflow} -> rabbit_channel:do(W, Method, Content) end. @@ -881,13 +872,13 @@ flush_writer(#state{driver = direct}) -> amqp_msg(none) -> none; amqp_msg(Content) -> - {Props, Payload} = rabbit_basic_common:from_content(Content), + {Props, Payload} = rabbit_basic:from_content(Content), #amqp_msg{props = Props, payload = Payload}. build_content(none) -> none; build_content(#amqp_msg{props = Props, payload = Payload}) -> - rabbit_basic_common:build_content(Props, Payload). + rabbit_basic:build_content(Props, Payload). check_block(_Method, _AmqpMsg, #state{closing = {just_channel, _}}) -> closing; diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_channel_sup.erl b/deps/amqp_client/src/amqp_channel_sup.erl similarity index 98% rename from rabbitmq-server/deps/amqp_client/src/amqp_channel_sup.erl rename to deps/amqp_client/src/amqp_channel_sup.erl index fe749e6..547b9fd 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_channel_sup.erl +++ b/deps/amqp_client/src/amqp_channel_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_channel_sup_sup.erl b/deps/amqp_client/src/amqp_channel_sup_sup.erl similarity index 91% rename from rabbitmq-server/deps/amqp_client/src/amqp_channel_sup_sup.erl rename to deps/amqp_client/src/amqp_channel_sup_sup.erl index a5ab241..a206c9f 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_channel_sup_sup.erl +++ b/deps/amqp_client/src/amqp_channel_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -42,4 +42,4 @@ init([Type, Connection, ConnName]) -> {ok, {{simple_one_for_one, 0, 1}, [{channel_sup, {amqp_channel_sup, start_link, [Type, Connection, ConnName]}, - temporary, infinity, supervisor, [amqp_channel_sup]}]}}. + temporary, brutal_kill, supervisor, [amqp_channel_sup]}]}}. diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_channels_manager.erl b/deps/amqp_client/src/amqp_channels_manager.erl similarity index 97% rename from rabbitmq-server/deps/amqp_client/src/amqp_channels_manager.erl rename to deps/amqp_client/src/amqp_channels_manager.erl index 145d0ae..ceb223a 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_channels_manager.erl +++ b/deps/amqp_client/src/amqp_channels_manager.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -63,10 +63,10 @@ signal_connection_closing(ChMgr, ChannelCloseType, Reason) -> process_channel_frame(Frame, Channel, ChPid, AState) -> case rabbit_command_assembler:process(Frame, AState) of {ok, NewAState} -> NewAState; - {ok, Method, NewAState} -> rabbit_channel_common:do(ChPid, Method), + {ok, Method, NewAState} -> rabbit_channel:do(ChPid, Method), NewAState; - {ok, Method, Content, NewAState} -> rabbit_channel_common:do(ChPid, Method, - Content), + {ok, Method, Content, NewAState} -> rabbit_channel:do(ChPid, Method, + Content), NewAState; {error, Reason} -> ChPid ! {channel_exit, Channel, Reason}, diff --git a/deps/amqp_client/src/amqp_client.app.src b/deps/amqp_client/src/amqp_client.app.src new file mode 100644 index 0000000..959e58c --- /dev/null +++ b/deps/amqp_client/src/amqp_client.app.src @@ -0,0 +1,9 @@ +{application, amqp_client, + [{description, "RabbitMQ AMQP Client"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, [amqp_sup]}, + {env, [{prefer_ipv6, false}, + {ssl_options, []}]}, + {mod, {amqp_client, []}}, + {applications, [kernel, stdlib, xmerl, rabbit_common]}]}. diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_client.erl b/deps/amqp_client/src/amqp_client.erl similarity index 77% rename from rabbitmq-server/deps/amqp_client/src/amqp_client.erl rename to deps/amqp_client/src/amqp_client.erl index f7151e7..0e0d141 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_client.erl +++ b/deps/amqp_client/src/amqp_client.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -27,13 +27,6 @@ %%--------------------------------------------------------------------------- start() -> - %% rabbit_common needs compiler and syntax_tools, see - %% - %% * https://github.com/rabbitmq/rabbitmq-erlang-client/issues/72 - %% * https://github.com/rabbitmq/rabbitmq-common/pull/149 - application:start(syntax_tools), - application:start(compiler), - application:start(xmerl), application:start(rabbit_common), application:start(amqp_client). diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_connection.erl b/deps/amqp_client/src/amqp_connection.erl similarity index 98% rename from rabbitmq-server/deps/amqp_client/src/amqp_connection.erl rename to deps/amqp_client/src/amqp_connection.erl index 65bfc7f..0dc0b70 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_connection.erl +++ b/deps/amqp_client/src/amqp_connection.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @type close_reason(Type) = {shutdown, amqp_reason(Type)}. @@ -157,7 +157,7 @@ start(AmqpParams) -> %% running in the same process space. If the port is set to 'undefined', %% the default ports will be selected depending on whether this is a %% normal or an SSL connection. -%% If ConnectionName is binary - it will be added to client_properties as +%% If ConnectionName is binary - it will be added to client_properties as %% user specified connection name. start(AmqpParams, ConnName) when ConnName == undefined; is_binary(ConnName) -> ensure_started(), @@ -175,13 +175,13 @@ start(AmqpParams, ConnName) when ConnName == undefined; is_binary(ConnName) -> amqp_gen_connection:connect(Connection). set_connection_name(undefined, Params) -> Params; -set_connection_name(ConnName, +set_connection_name(ConnName, #amqp_params_network{client_properties = Props} = Params) -> Params#amqp_params_network{ client_properties = [ {<<"connection_name">>, longstr, ConnName} | Props ]}; -set_connection_name(ConnName, +set_connection_name(ConnName, #amqp_params_direct{client_properties = Props} = Params) -> Params#amqp_params_direct{ client_properties = [ @@ -195,8 +195,7 @@ set_connection_name(ConnName, %% application controller is in the process of shutting down the very %% application which is making this call. ensure_started() -> - [ensure_started(App) || App <- [syntax_tools, compiler, xmerl, - rabbit_common, amqp_client]]. + [ensure_started(App) || App <- [xmerl, rabbit_common, amqp_client]]. ensure_started(App) -> case is_pid(application_controller:get_master(App)) andalso amqp_sup:is_ready() of diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_connection_sup.erl b/deps/amqp_client/src/amqp_connection_sup.erl similarity index 96% rename from rabbitmq-server/deps/amqp_client/src/amqp_connection_sup.erl rename to deps/amqp_client/src/amqp_connection_sup.erl index a6d3608..be9da63 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_connection_sup.erl +++ b/deps/amqp_client/src/amqp_connection_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_connection_type_sup.erl b/deps/amqp_client/src/amqp_connection_type_sup.erl similarity index 98% rename from rabbitmq-server/deps/amqp_client/src/amqp_connection_type_sup.erl rename to deps/amqp_client/src/amqp_connection_type_sup.erl index a21d686..636e81a 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_connection_type_sup.erl +++ b/deps/amqp_client/src/amqp_connection_type_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_direct_connection.erl b/deps/amqp_client/src/amqp_direct_connection.erl similarity index 94% rename from rabbitmq-server/deps/amqp_client/src/amqp_direct_connection.erl rename to deps/amqp_client/src/amqp_direct_connection.erl index e2f3b6e..15491b8 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_direct_connection.erl +++ b/deps/amqp_client/src/amqp_direct_connection.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -78,8 +78,6 @@ handle_message({'DOWN', _MRef, process, _ConnSup, shutdown}, State) -> {stop, {shutdown, node_down}, State}; handle_message({'DOWN', _MRef, process, _ConnSup, Reason}, State) -> {stop, {remote_node_down, Reason}, State}; -handle_message({'EXIT', Pid, Reason}, State) -> - {stop, rabbit_misc:format("stopping because dependent process ~p died: ~p", [Pid, Reason]), State}; handle_message(Msg, State) -> {stop, {unexpected_msg, Msg}, State}. @@ -88,7 +86,7 @@ closing(_ChannelCloseType, Reason, State) -> channels_terminated(State = #state{closing_reason = Reason, collector = Collector}) -> - rabbit_queue_collector_common:delete_all(Collector), + rabbit_queue_collector:delete_all(Collector), {stop, {shutdown, Reason}, State}. terminate(_Reason, #state{node = Node}) -> @@ -214,11 +212,11 @@ ssl_cert_info(Sock) -> case rabbit_net:peercert(Sock) of {ok, Cert} -> [{peer_cert_issuer, list_to_binary( - rabbit_cert_info:issuer(Cert))}, + rabbit_ssl:peer_cert_issuer(Cert))}, {peer_cert_subject, list_to_binary( - rabbit_cert_info:subject(Cert))}, + rabbit_ssl:peer_cert_subject(Cert))}, {peer_cert_validity, list_to_binary( - rabbit_cert_info:validity(Cert))}]; + rabbit_ssl:peer_cert_validity(Cert))}]; _ -> [] end. diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_direct_consumer.erl b/deps/amqp_client/src/amqp_direct_consumer.erl similarity index 100% rename from rabbitmq-server/deps/amqp_client/src/amqp_direct_consumer.erl rename to deps/amqp_client/src/amqp_direct_consumer.erl diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_gen_connection.erl b/deps/amqp_client/src/amqp_gen_connection.erl similarity index 95% rename from rabbitmq-server/deps/amqp_client/src/amqp_gen_connection.erl rename to deps/amqp_client/src/amqp_gen_connection.erl index 9af6d77..2829248 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_gen_connection.erl +++ b/deps/amqp_client/src/amqp_gen_connection.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -221,18 +221,9 @@ handle_cast({register_blocked_handler, HandlerPid}, State) -> %% @private handle_info({'DOWN', _, process, BlockHandler, Reason}, State = #state{block_handler = {BlockHandler, _Ref}}) -> - ?LOG_WARN("Connection (~p): Unregistering connection.{blocked,unblocked} handler ~p because it died. " + ?LOG_WARN("Connection (~p): Unregistering block handler ~p because it died. " "Reason: ~p~n", [self(), BlockHandler, Reason]), {noreply, State#state{block_handler = none}}; -handle_info({'EXIT', BlockHandler, Reason}, - State = #state{block_handler = {BlockHandler, Ref}}) -> - ?LOG_WARN("Connection (~p): Unregistering connection.{blocked,unblocked} handler ~p because it died. " - "Reason: ~p~n", [self(), BlockHandler, Reason]), - erlang:demonitor(Ref, [flush]), - {noreply, State#state{block_handler = none}}; -%% propagate the exit to the module that will stop with a sensible reason logged -handle_info({'EXIT', _Pid, _Reason} = Info, State) -> - callback(handle_message, [Info], State); handle_info(Info, State) -> callback(handle_message, [Info], State). diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_gen_consumer.erl b/deps/amqp_client/src/amqp_gen_consumer.erl similarity index 100% rename from rabbitmq-server/deps/amqp_client/src/amqp_gen_consumer.erl rename to deps/amqp_client/src/amqp_gen_consumer.erl diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_main_reader.erl b/deps/amqp_client/src/amqp_main_reader.erl similarity index 98% rename from rabbitmq-server/deps/amqp_client/src/amqp_main_reader.erl rename to deps/amqp_client/src/amqp_main_reader.erl index 4f0cfaa..33a6947 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_main_reader.erl +++ b/deps/amqp_client/src/amqp_main_reader.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_network_connection.erl b/deps/amqp_client/src/amqp_network_connection.erl similarity index 96% rename from rabbitmq-server/deps/amqp_client/src/amqp_network_connection.erl rename to deps/amqp_client/src/amqp_network_connection.erl index 2ef943e..c08e9db 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_network_connection.erl +++ b/deps/amqp_client/src/amqp_network_connection.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private @@ -73,8 +73,6 @@ handle_message(heartbeat_timeout, State) -> {stop, heartbeat_timeout, State}; handle_message(closing_timeout, State = #state{closing_reason = Reason}) -> {stop, Reason, State}; -handle_message({'EXIT', Pid, Reason}, State) -> - {stop, rabbit_misc:format("stopping because dependent process ~p died: ~p", [Pid, Reason]), State}; %% see http://erlang.org/pipermail/erlang-bugs/2012-June/002933.html handle_message({Ref, {error, Reason}}, State = #state{waiting_socket_close = Waiting, @@ -86,9 +84,6 @@ handle_message({Ref, {error, Reason}}, {_, _} -> {socket_error, Reason} end, State}. -closing(_ChannelCloseType, {server_initiated_close, _, _} = Reason, State) -> - {ok, State#state{waiting_socket_close = true, - closing_reason = Reason}}; closing(_ChannelCloseType, Reason, State) -> {ok, State#state{closing_reason = Reason}}. @@ -149,7 +144,7 @@ do_connect({Addr, Family}, [Family | ?RABBIT_TCP_OPTS] ++ ExtraOpts, Timeout) of {ok, Sock} -> - SslOpts = rabbit_ssl_options:fix( + SslOpts = rabbit_networking:fix_ssl_options( orddict:to_list( orddict:merge(fun (_, _A, B) -> B end, orddict:from_list(GlobalSslOpts), @@ -308,7 +303,7 @@ client_properties(UserProperties) -> {<<"version">>, longstr, list_to_binary(Vsn)}, {<<"platform">>, longstr, <<"Erlang">>}, {<<"copyright">>, longstr, - <<"Copyright (c) 2007-2017 Pivotal Software, Inc.">>}, + <<"Copyright (c) 2007-2016 Pivotal Software, Inc.">>}, {<<"information">>, longstr, <<"Licensed under the MPL. " "See http://www.rabbitmq.com/">>}, diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_rpc_client.erl b/deps/amqp_client/src/amqp_rpc_client.erl similarity index 99% rename from rabbitmq-server/deps/amqp_client/src/amqp_rpc_client.erl rename to deps/amqp_client/src/amqp_rpc_client.erl index c603d98..6fadba8 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_rpc_client.erl +++ b/deps/amqp_client/src/amqp_rpc_client.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @doc This module allows the simple execution of an asynchronous RPC over diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_rpc_server.erl b/deps/amqp_client/src/amqp_rpc_server.erl similarity index 98% rename from rabbitmq-server/deps/amqp_client/src/amqp_rpc_server.erl rename to deps/amqp_client/src/amqp_rpc_server.erl index 0107403..25be89e 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_rpc_server.erl +++ b/deps/amqp_client/src/amqp_rpc_server.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @doc This is a utility module that is used to expose an arbitrary function diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_selective_consumer.erl b/deps/amqp_client/src/amqp_selective_consumer.erl similarity index 100% rename from rabbitmq-server/deps/amqp_client/src/amqp_selective_consumer.erl rename to deps/amqp_client/src/amqp_selective_consumer.erl diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_sup.erl b/deps/amqp_client/src/amqp_sup.erl similarity index 95% rename from rabbitmq-server/deps/amqp_client/src/amqp_sup.erl rename to deps/amqp_client/src/amqp_sup.erl index 9e92ab3..1a02981 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_sup.erl +++ b/deps/amqp_client/src/amqp_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% @private diff --git a/rabbitmq-server/deps/amqp_client/src/amqp_uri.erl b/deps/amqp_client/src/amqp_uri.erl similarity index 93% rename from rabbitmq-server/deps/amqp_client/src/amqp_uri.erl rename to deps/amqp_client/src/amqp_uri.erl index f224a45..95447ab 100644 --- a/rabbitmq-server/deps/amqp_client/src/amqp_uri.erl +++ b/deps/amqp_client/src/amqp_uri.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(amqp_uri). @@ -26,10 +26,8 @@ %% Reformat a URI to remove authentication secrets from it (before we %% log it or display it anywhere). --spec remove_credentials(URI :: string() | binary()) -> string(). remove_credentials(URI) -> - UriString = rabbit_data_coercion:to_list(URI), - Props = uri_parser:parse(UriString, + Props = uri_parser:parse(URI, [{host, undefined}, {path, undefined}, {port, undefined}, {'query', []}]), PortPart = case proplists:get_value(port, Props) of @@ -64,23 +62,16 @@ remove_credentials(URI) -> %% than once). The extra parameters that may be specified for an SSL %% connection are cacertfile, certfile, keyfile, verify, %% fail_if_no_peer_cert, password, and depth. --type parse_result() :: {ok, #amqp_params_network{}} | - {ok, #amqp_params_direct{}} | - {error, {any(), string()}}. - --spec parse(Uri :: string() | binary()) -> parse_result(). parse(Uri) -> parse(Uri, <<"/">>). --spec parse(Uri :: string() | binary(), DefaultVHost :: binary()) -> parse_result(). parse(Uri, DefaultVHost) -> try return(parse1(Uri, DefaultVHost)) catch throw:Err -> {error, {Err, Uri}}; error:Err -> {error, {Err, Uri}} end. -parse1(Uri, DefaultVHost) when is_list(Uri); is_binary(Uri) -> - UriString = rabbit_data_coercion:to_list(Uri), - case uri_parser:parse(UriString, [{host, undefined}, {path, undefined}, +parse1(Uri, DefaultVHost) when is_list(Uri) -> + case uri_parser:parse(Uri, [{host, undefined}, {path, undefined}, {port, undefined}, {'query', []}]) of {error, Err} -> throw({unable_to_parse_uri, Err}); diff --git a/rabbitmq-server/deps/amqp_client/src/overview.edoc.in b/deps/amqp_client/src/overview.edoc.in similarity index 100% rename from rabbitmq-server/deps/amqp_client/src/overview.edoc.in rename to deps/amqp_client/src/overview.edoc.in diff --git a/rabbitmq-server/deps/amqp_client/src/rabbit_routing_util.erl b/deps/amqp_client/src/rabbit_routing_util.erl similarity index 100% rename from rabbitmq-server/deps/amqp_client/src/rabbit_routing_util.erl rename to deps/amqp_client/src/rabbit_routing_util.erl diff --git a/rabbitmq-server/deps/amqp_client/src/uri_parser.erl b/deps/amqp_client/src/uri_parser.erl similarity index 96% rename from rabbitmq-server/deps/amqp_client/src/uri_parser.erl rename to deps/amqp_client/src/uri_parser.erl index c98cdb6..ee83073 100644 --- a/rabbitmq-server/deps/amqp_client/src/uri_parser.erl +++ b/deps/amqp_client/src/uri_parser.erl @@ -39,10 +39,8 @@ %% are: 'scheme', 'userinfo', 'host', 'port', 'path', 'query', %% 'fragment'. --spec parse(AbsURI :: string() | binary(), Defaults :: list()) -> string(). parse(AbsURI, Defaults) -> - AbsUriString = rabbit_data_coercion:to_list(AbsURI), - case parse_scheme(AbsUriString) of + case parse_scheme(AbsURI) of {error, Reason} -> {error, Reason}; {Scheme, Rest} -> diff --git a/rabbitmq-server/deps/cowboy/AUTHORS b/deps/cowboy/AUTHORS similarity index 100% rename from rabbitmq-server/deps/cowboy/AUTHORS rename to deps/cowboy/AUTHORS diff --git a/rabbitmq-server/deps/cowboy/CHANGELOG.md b/deps/cowboy/CHANGELOG.md similarity index 99% rename from rabbitmq-server/deps/cowboy/CHANGELOG.md rename to deps/cowboy/CHANGELOG.md index 117333b..edeb748 100644 --- a/rabbitmq-server/deps/cowboy/CHANGELOG.md +++ b/deps/cowboy/CHANGELOG.md @@ -1,11 +1,6 @@ CHANGELOG ========= -1.0.4 ------ - - * Fix a crash when using iolist() as payload for some Websocket frames - 1.0.3 ----- diff --git a/rabbitmq-server/deps/cowboy/CONTRIBUTING.md b/deps/cowboy/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/cowboy/CONTRIBUTING.md rename to deps/cowboy/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/cowboy/LICENSE b/deps/cowboy/LICENSE similarity index 100% rename from rabbitmq-server/deps/cowboy/LICENSE rename to deps/cowboy/LICENSE diff --git a/rabbitmq-server/deps/cowboy/Makefile b/deps/cowboy/Makefile similarity index 97% rename from rabbitmq-server/deps/cowboy/Makefile rename to deps/cowboy/Makefile index db9f37b..a186286 100644 --- a/rabbitmq-server/deps/cowboy/Makefile +++ b/deps/cowboy/Makefile @@ -20,7 +20,7 @@ dep_gun = git https://github.com/ninenines/gun b85c1f726ca49ac0e3abdcf717317cb95 # Standard targets. -include $(if $(ERLANG_MK_FILENAME),$(ERLANG_MK_FILENAME),erlang.mk) +include erlang.mk # Documentation. diff --git a/rabbitmq-server/deps/cowboy/README.md b/deps/cowboy/README.md similarity index 100% rename from rabbitmq-server/deps/cowboy/README.md rename to deps/cowboy/README.md diff --git a/rabbitmq-server/deps/cowboy/ROADMAP.md b/deps/cowboy/ROADMAP.md similarity index 100% rename from rabbitmq-server/deps/cowboy/ROADMAP.md rename to deps/cowboy/ROADMAP.md diff --git a/rabbitmq-server/deps/cowboy/all.sh b/deps/cowboy/all.sh similarity index 100% rename from rabbitmq-server/deps/cowboy/all.sh rename to deps/cowboy/all.sh diff --git a/rabbitmq-server/deps/cowboy/circle.yml b/deps/cowboy/circle.yml similarity index 94% rename from rabbitmq-server/deps/cowboy/circle.yml rename to deps/cowboy/circle.yml index c18b8f8..fa31fe2 100644 --- a/rabbitmq-server/deps/cowboy/circle.yml +++ b/deps/cowboy/circle.yml @@ -9,7 +9,6 @@ dependencies: pre: - sudo pip install autobahntestsuite - - sudo apt-get update - sudo apt-get install autoconf2.59 - cd $HOME/bin && ln -s /usr/bin/autoconf2.59 autoconf - cd $HOME/bin && ln -s /usr/bin/autoheader2.59 autoheader diff --git a/deps/cowboy/erlang.mk b/deps/cowboy/erlang.mk new file mode 100644 index 0000000..8930dfc --- /dev/null +++ b/deps/cowboy/erlang.mk @@ -0,0 +1 @@ +include ../../erlang.mk diff --git a/rabbitmq-server/deps/cowboy/rebar.config b/deps/cowboy/rebar.config similarity index 100% rename from rabbitmq-server/deps/cowboy/rebar.config rename to deps/cowboy/rebar.config diff --git a/rabbitmq-server/deps/cowboy/src/cowboy.app.src b/deps/cowboy/src/cowboy.app.src similarity index 91% rename from rabbitmq-server/deps/cowboy/src/cowboy.app.src rename to deps/cowboy/src/cowboy.app.src index 40c4e14..b3f3c56 100644 --- a/rabbitmq-server/deps/cowboy/src/cowboy.app.src +++ b/deps/cowboy/src/cowboy.app.src @@ -1,6 +1,6 @@ {application,cowboy, [{description,"Small, fast, modular HTTP server."}, - {vsn,"1.0.4"}, + {vsn,"1.0.3"}, {id,"git"}, {modules,[]}, {registered,[cowboy_clock,cowboy_sup]}, diff --git a/rabbitmq-server/deps/cowboy/src/cowboy.erl b/deps/cowboy/src/cowboy.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy.erl rename to deps/cowboy/src/cowboy.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_app.erl b/deps/cowboy/src/cowboy_app.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_app.erl rename to deps/cowboy/src/cowboy_app.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_bstr.erl b/deps/cowboy/src/cowboy_bstr.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_bstr.erl rename to deps/cowboy/src/cowboy_bstr.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_clock.erl b/deps/cowboy/src/cowboy_clock.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_clock.erl rename to deps/cowboy/src/cowboy_clock.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_handler.erl b/deps/cowboy/src/cowboy_handler.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_handler.erl rename to deps/cowboy/src/cowboy_handler.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_http.erl b/deps/cowboy/src/cowboy_http.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_http.erl rename to deps/cowboy/src/cowboy_http.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_http_handler.erl b/deps/cowboy/src/cowboy_http_handler.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_http_handler.erl rename to deps/cowboy/src/cowboy_http_handler.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_loop_handler.erl b/deps/cowboy/src/cowboy_loop_handler.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_loop_handler.erl rename to deps/cowboy/src/cowboy_loop_handler.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_middleware.erl b/deps/cowboy/src/cowboy_middleware.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_middleware.erl rename to deps/cowboy/src/cowboy_middleware.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_protocol.erl b/deps/cowboy/src/cowboy_protocol.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_protocol.erl rename to deps/cowboy/src/cowboy_protocol.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_req.erl b/deps/cowboy/src/cowboy_req.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_req.erl rename to deps/cowboy/src/cowboy_req.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_rest.erl b/deps/cowboy/src/cowboy_rest.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_rest.erl rename to deps/cowboy/src/cowboy_rest.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_router.erl b/deps/cowboy/src/cowboy_router.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_router.erl rename to deps/cowboy/src/cowboy_router.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_spdy.erl b/deps/cowboy/src/cowboy_spdy.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_spdy.erl rename to deps/cowboy/src/cowboy_spdy.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_static.erl b/deps/cowboy/src/cowboy_static.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_static.erl rename to deps/cowboy/src/cowboy_static.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_sub_protocol.erl b/deps/cowboy/src/cowboy_sub_protocol.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_sub_protocol.erl rename to deps/cowboy/src/cowboy_sub_protocol.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_sup.erl b/deps/cowboy/src/cowboy_sup.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_sup.erl rename to deps/cowboy/src/cowboy_sup.erl diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_websocket.erl b/deps/cowboy/src/cowboy_websocket.erl similarity index 99% rename from rabbitmq-server/deps/cowboy/src/cowboy_websocket.erl rename to deps/cowboy/src/cowboy_websocket.erl index 9577086..c0f94c4 100644 --- a/rabbitmq-server/deps/cowboy/src/cowboy_websocket.erl +++ b/deps/cowboy/src/cowboy_websocket.erl @@ -570,7 +570,7 @@ websocket_dispatch(State, Req, HandlerState, _RemainingData, 8, %% Ping control frame. Send a pong back and forward the ping to the handler. websocket_dispatch(State=#state{socket=Socket, transport=Transport}, Req, HandlerState, RemainingData, 9, Payload) -> - Len = payload_length_to_binary(iolist_size(Payload)), + Len = payload_length_to_binary(byte_size(Payload)), Transport:send(Socket, << 1:1, 0:3, 10:4, 0:1, Len/bits, Payload/binary >>), handler_call(State, Req, HandlerState, RemainingData, websocket_handle, {ping, Payload}, fun websocket_data/4); diff --git a/rabbitmq-server/deps/cowboy/src/cowboy_websocket_handler.erl b/deps/cowboy/src/cowboy_websocket_handler.erl similarity index 100% rename from rabbitmq-server/deps/cowboy/src/cowboy_websocket_handler.erl rename to deps/cowboy/src/cowboy_websocket_handler.erl diff --git a/rabbitmq-server/deps/cowlib/AUTHORS b/deps/cowlib/AUTHORS similarity index 78% rename from rabbitmq-server/deps/cowlib/AUTHORS rename to deps/cowlib/AUTHORS index 556636d..824ec87 100644 --- a/rabbitmq-server/deps/cowlib/AUTHORS +++ b/deps/cowlib/AUTHORS @@ -1,5 +1,4 @@ Cowlib is available thanks to the work of: Loïc Hoguin -Krzysztof Jurewicz Mikkel Jensen diff --git a/rabbitmq-server/deps/cowlib/CHANGELOG.md b/deps/cowlib/CHANGELOG.md similarity index 64% rename from rabbitmq-server/deps/cowlib/CHANGELOG.md rename to deps/cowlib/CHANGELOG.md index 8b18c24..88146e9 100644 --- a/rabbitmq-server/deps/cowlib/CHANGELOG.md +++ b/deps/cowlib/CHANGELOG.md @@ -1,11 +1,6 @@ CHANGELOG ========= -1.0.2 ------ - - * Fix handling of default values in cookie options - 1.0.1 ----- diff --git a/rabbitmq-server/deps/cowlib/LICENSE b/deps/cowlib/LICENSE similarity index 100% rename from rabbitmq-server/deps/cowlib/LICENSE rename to deps/cowlib/LICENSE diff --git a/rabbitmq-server/deps/cowlib/Makefile b/deps/cowlib/Makefile similarity index 79% rename from rabbitmq-server/deps/cowlib/Makefile rename to deps/cowlib/Makefile index 87d77b9..8b1d1b4 100644 --- a/rabbitmq-server/deps/cowlib/Makefile +++ b/deps/cowlib/Makefile @@ -2,11 +2,8 @@ PROJECT = cowlib PLT_APPS = crypto -CI_OTP = OTP_R15B OTP_R15B01 OTP_R15B02 OTP_R15B03-1 OTP_R16B OTP_R16B01 OTP_R16B02 OTP_R16B03-1 OTP-17.0.2 OTP-17.1.2 OTP-17.2.2 OTP-17.3.4 OTP-17.4.1 OTP-17.5.6.3 OTP-18.0.3 -include $(if $(ERLANG_MK_FILENAME),$(ERLANG_MK_FILENAME),erlang.mk) - -TEST_ERLC_OPTS += +'{parse_transform, eunit_autoexport}' -DEXTRA=1 +include erlang.mk .PHONY: gen perfs diff --git a/rabbitmq-server/deps/cowlib/README.md b/deps/cowlib/README.md similarity index 100% rename from rabbitmq-server/deps/cowlib/README.md rename to deps/cowlib/README.md diff --git a/deps/cowlib/all.sh b/deps/cowlib/all.sh new file mode 100755 index 0000000..fa9dd16 --- /dev/null +++ b/deps/cowlib/all.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +KERL_INSTALL_PATH=~/erlang +KERL_RELEASES="r15b r15b01 r15b02 r15b03 r16b r16b01 r16b02 r16b03-1 17.0 17.1.2" + +make build-ct-suites + +for rel in $KERL_RELEASES +do + echo + echo " TESTING $rel" + echo + . $KERL_INSTALL_PATH/$rel/activate + CT_OPTS="-label $rel" make tests +done + +xdg-open logs/all_runs.html diff --git a/deps/cowlib/build.config b/deps/cowlib/build.config new file mode 100644 index 0000000..87fd50d --- /dev/null +++ b/deps/cowlib/build.config @@ -0,0 +1,20 @@ +# Core modules. +# +# Do *not* comment or remove them +# unless you know what you are doing! +core/core +core/deps +core/erlc + +# Plugins. +# +# Comment to disable, uncomment to enable. +plugins/bootstrap +#plugins/c_src +plugins/ct +plugins/dialyzer +#plugins/edoc +plugins/elvis +#plugins/erlydtl +#plugins/relx +plugins/shell diff --git a/deps/cowlib/erlang.mk b/deps/cowlib/erlang.mk new file mode 100644 index 0000000..8930dfc --- /dev/null +++ b/deps/cowlib/erlang.mk @@ -0,0 +1 @@ +include ../../erlang.mk diff --git a/rabbitmq-server/deps/cowlib/include/cow_inline.hrl b/deps/cowlib/include/cow_inline.hrl similarity index 100% rename from rabbitmq-server/deps/cowlib/include/cow_inline.hrl rename to deps/cowlib/include/cow_inline.hrl diff --git a/rabbitmq-server/deps/cowlib/src/cow_cookie.erl b/deps/cowlib/src/cow_cookie.erl similarity index 97% rename from rabbitmq-server/deps/cowlib/src/cow_cookie.erl rename to deps/cowlib/src/cow_cookie.erl index 4e36ec4..6db89be 100644 --- a/rabbitmq-server/deps/cowlib/src/cow_cookie.erl +++ b/deps/cowlib/src/cow_cookie.erl @@ -197,12 +197,10 @@ setcookie(Name, Value, Opts) -> end, SecureBin = case lists:keyfind(secure, 1, Opts) of false -> <<>>; - {_, false} -> <<>>; {_, true} -> <<"; Secure">> end, HttpOnlyBin = case lists:keyfind(http_only, 1, Opts) of false -> <<>>; - {_, false} -> <<>>; {_, true} -> <<"; HttpOnly">> end, [Name, <<"=">>, Value, <<"; Version=1">>, @@ -219,12 +217,6 @@ setcookie_test_() -> {<<"Customer">>, <<"WILE_E_COYOTE">>, [{path, <<"/acme">>}], <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>}, - {<<"Customer">>, <<"WILE_E_COYOTE">>, - [{secure, true}], - <<"Customer=WILE_E_COYOTE; Version=1; Secure">>}, - {<<"Customer">>, <<"WILE_E_COYOTE">>, - [{secure, false}, {http_only, false}], - <<"Customer=WILE_E_COYOTE; Version=1">>}, {<<"Customer">>, <<"WILE_E_COYOTE">>, [{path, <<"/acme">>}, {badoption, <<"negatory">>}], <<"Customer=WILE_E_COYOTE; Version=1; Path=/acme">>} diff --git a/rabbitmq-server/deps/cowlib/src/cow_date.erl b/deps/cowlib/src/cow_date.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_date.erl rename to deps/cowlib/src/cow_date.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_http.erl b/deps/cowlib/src/cow_http.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_http.erl rename to deps/cowlib/src/cow_http.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_http_hd.erl b/deps/cowlib/src/cow_http_hd.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_http_hd.erl rename to deps/cowlib/src/cow_http_hd.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_http_te.erl b/deps/cowlib/src/cow_http_te.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_http_te.erl rename to deps/cowlib/src/cow_http_te.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_mimetypes.erl b/deps/cowlib/src/cow_mimetypes.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_mimetypes.erl rename to deps/cowlib/src/cow_mimetypes.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_mimetypes.erl.src b/deps/cowlib/src/cow_mimetypes.erl.src similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_mimetypes.erl.src rename to deps/cowlib/src/cow_mimetypes.erl.src diff --git a/rabbitmq-server/deps/cowlib/src/cow_multipart.erl b/deps/cowlib/src/cow_multipart.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_multipart.erl rename to deps/cowlib/src/cow_multipart.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_qs.erl b/deps/cowlib/src/cow_qs.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_qs.erl rename to deps/cowlib/src/cow_qs.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_spdy.erl b/deps/cowlib/src/cow_spdy.erl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_spdy.erl rename to deps/cowlib/src/cow_spdy.erl diff --git a/rabbitmq-server/deps/cowlib/src/cow_spdy.hrl b/deps/cowlib/src/cow_spdy.hrl similarity index 100% rename from rabbitmq-server/deps/cowlib/src/cow_spdy.hrl rename to deps/cowlib/src/cow_spdy.hrl diff --git a/rabbitmq-server/deps/cowlib/src/cowlib.app.src b/deps/cowlib/src/cowlib.app.src similarity index 89% rename from rabbitmq-server/deps/cowlib/src/cowlib.app.src rename to deps/cowlib/src/cowlib.app.src index dbba197..7545fc7 100644 --- a/rabbitmq-server/deps/cowlib/src/cowlib.app.src +++ b/deps/cowlib/src/cowlib.app.src @@ -1,6 +1,6 @@ {application,cowlib, [{description,"Support library for manipulating Web protocols."}, - {vsn,"1.0.2"}, + {vsn,"1.0.1"}, {id,"git"}, {modules,[]}, {registered,[]}, diff --git a/rabbitmq-server/deps/licensing/LICENSE-APACHE2-ExplorerCanvas b/deps/licensing/LICENSE-APACHE2-ExplorerCanvas similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-APACHE2-ExplorerCanvas rename to deps/licensing/LICENSE-APACHE2-ExplorerCanvas diff --git a/rabbitmq-server/deps/licensing/LICENSE-APL2-Rebar b/deps/licensing/LICENSE-APL2-Rebar similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-APL2-Rebar rename to deps/licensing/LICENSE-APL2-Rebar diff --git a/rabbitmq-server/deps/licensing/LICENSE-APL2-Stomp-Websocket b/deps/licensing/LICENSE-APL2-Stomp-Websocket similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-APL2-Stomp-Websocket rename to deps/licensing/LICENSE-APL2-Stomp-Websocket diff --git a/rabbitmq-server/deps/licensing/LICENSE-BSD-base64js b/deps/licensing/LICENSE-BSD-base64js similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-BSD-base64js rename to deps/licensing/LICENSE-BSD-base64js diff --git a/rabbitmq-server/deps/licensing/LICENSE-BSD-glMatrix b/deps/licensing/LICENSE-BSD-glMatrix similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-BSD-glMatrix rename to deps/licensing/LICENSE-BSD-glMatrix diff --git a/rabbitmq-server/deps/licensing/LICENSE-EPL-OTP b/deps/licensing/LICENSE-EPL-OTP similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-EPL-OTP rename to deps/licensing/LICENSE-EPL-OTP diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-EJS10 b/deps/licensing/LICENSE-MIT-EJS10 similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-EJS10 rename to deps/licensing/LICENSE-MIT-EJS10 diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-Erlware-Commons b/deps/licensing/LICENSE-MIT-Erlware-Commons similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-Erlware-Commons rename to deps/licensing/LICENSE-MIT-Erlware-Commons diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-Flot b/deps/licensing/LICENSE-MIT-Flot similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-Flot rename to deps/licensing/LICENSE-MIT-Flot diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-Mochi b/deps/licensing/LICENSE-MIT-Mochi similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-Mochi rename to deps/licensing/LICENSE-MIT-Mochi diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-Mochiweb b/deps/licensing/LICENSE-MIT-Mochiweb similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-Mochiweb rename to deps/licensing/LICENSE-MIT-Mochiweb diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-Sammy060 b/deps/licensing/LICENSE-MIT-Sammy060 similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-Sammy060 rename to deps/licensing/LICENSE-MIT-Sammy060 diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-SockJS b/deps/licensing/LICENSE-MIT-SockJS similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-SockJS rename to deps/licensing/LICENSE-MIT-SockJS diff --git a/rabbitmq-server/deps/licensing/LICENSE-MIT-jQuery164 b/deps/licensing/LICENSE-MIT-jQuery164 similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MIT-jQuery164 rename to deps/licensing/LICENSE-MIT-jQuery164 diff --git a/rabbitmq-server/deps/licensing/LICENSE-MPL-RabbitMQ b/deps/licensing/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MPL-RabbitMQ rename to deps/licensing/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/licensing/LICENSE-MPL2 b/deps/licensing/LICENSE-MPL2 similarity index 100% rename from rabbitmq-server/deps/licensing/LICENSE-MPL2 rename to deps/licensing/LICENSE-MPL2 diff --git a/rabbitmq-server/deps/licensing/license_info_rabbitmq_codegen b/deps/licensing/license_info_rabbitmq_codegen similarity index 100% rename from rabbitmq-server/deps/licensing/license_info_rabbitmq_codegen rename to deps/licensing/license_info_rabbitmq_codegen diff --git a/rabbitmq-server/deps/licensing/license_info_rabbitmq_management b/deps/licensing/license_info_rabbitmq_management similarity index 100% rename from rabbitmq-server/deps/licensing/license_info_rabbitmq_management rename to deps/licensing/license_info_rabbitmq_management diff --git a/rabbitmq-server/deps/licensing/license_info_rabbitmq_management_visualiser b/deps/licensing/license_info_rabbitmq_management_visualiser similarity index 100% rename from rabbitmq-server/deps/licensing/license_info_rabbitmq_management_visualiser rename to deps/licensing/license_info_rabbitmq_management_visualiser diff --git a/deps/mochiweb/.editorconfig b/deps/mochiweb/.editorconfig new file mode 100644 index 0000000..d03550e --- /dev/null +++ b/deps/mochiweb/.editorconfig @@ -0,0 +1,17 @@ +# EditorConfig file: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +# 4 space indentation +[*.{erl,src,hrl}] +indent_style = space +indent_size = 4 diff --git a/deps/mochiweb/CHANGES.md b/deps/mochiweb/CHANGES.md new file mode 100644 index 0000000..1b88f92 --- /dev/null +++ b/deps/mochiweb/CHANGES.md @@ -0,0 +1,206 @@ +Version 2.13.1 released 2016-03-13 + +* Fix mochiweb_html regression parsing invalid charref sequences + https://github.com/mochi/mochiweb/issues/167 + +Version 2.13.0 released 2016-02-08 + +* Support parsing of UTF-16 surrogate pairs encoded as character + references in mochiweb_html + https://github.com/mochi/mochiweb/issues/164 +* Avoid swallowing messages that are not related to the socket + during request parsing + https://github.com/mochi/mochiweb/pull/161 +* Ensure correct ordering of Set-Cookie headers: first in, first out + https://github.com/mochi/mochiweb/issues/162 +* Improve response times by caching a formatted date once per second + for the response headers with a mochiweb_clock service + https://github.com/mochi/mochiweb/pull/158 + +Version 2.12.2 released 2015-02-21 + +* Close connections quietly when setopts fails with a closed socket. + https://github.com/mochi/mochiweb/pull/152 + +Version 2.12.1 released 2015-02-01 + +* Fix active_socket accounting + https://github.com/mochi/mochiweb/issues/149 +* Added full MIT license preludes to each source file to make it + easier for mochiweb's code to be used piecemeal + https://github.com/mochi/mochiweb/pull/148 + +Version 2.12.0 released 2015-01-16 + +* Send "Connection: close" header when the server is going to close + a Keep-Alive connection, usually due to unread data from the + client + https://github.com/mochi/mochiweb/issues/146 + +Version 2.11.2 released 2015-01-16 + +* Fix regression introduced in #147 + https://github.com/mochi/mochiweb/pull/147 + +Version 2.11.1 released 2015-01-16 + +* Accept range end position which exceededs the resource size + https://github.com/mochi/mochiweb/pull/147 + +Version 2.11.0 released 2015-01-12 + +* Perform SSL handshake after releasing acceptor back into the pool, + and slow accept rate when file descriptors are not available, + to mitigate a potential DoS attack. Adds new mochiweb_socket + functions transport_accept/1 and finish_accept/1 which should be + used in preference to the now deprecated accept/1 function. + https://github.com/mochi/mochiweb/issues/138 + +Version 2.10.1 released 2015-01-11 + +* Fixes issue with SSL and mochiweb_websocket. Note that + mochiweb_websocket is still experimental and the API + is subject to change in future versions. + https://github.com/mochi/mochiweb/pull/144 + +Version 2.10.0 released 2014-12-17 + +* Added new `recbuf` option to mochiweb_http to allow the receive + buffer to be configured. + https://github.com/mochi/mochiweb/pull/134 + +Version 2.9.2 released 2014-10-16 + +* Add timeouts to SSL connect to prevent DoS by opening a connection + and not doing anything. + https://github.com/mochi/mochiweb/pull/140 +* Prevent using ECDH cipher in R16B because it is broken + https://github.com/mochi/mochiweb/pull/140 +* For default SSL connections, remove usage of sslv3 and not-so-secure + ciphers. + https://github.com/mochi/mochiweb/pull/140 + +Version 2.9.1 released 2014-09-29 + +* Fix Makefile rule for building docs + https://github.com/mochi/mochiweb/issues/135 +* Minimize gen_tcp:send calls to optimize performance. + https://github.com/mochi/mochiweb/pull/137 + +Version 2.9.0 released 2014-06-24 + +* Increased timeout in test suite for FreeBSD + https://github.com/mochi/mochiweb/pull/121 +* Updated rebar to v2.5.0 and fixed associated build issues + https://github.com/mochi/mochiweb/issues/131 + +Version 2.8.0 released 2014-01-01 + +* Websocket support + https://github.com/mochi/mochiweb/pull/120 +* Force files named "crossdomain.xml" to have MIME type + text/x-cross-domain-policy. + https://github.com/mochi/mochiweb/pull/118 + +Version 2.7.0 released 2013-08-01 + +* Fix 0-length range responses + https://github.com/mochi/mochiweb/pull/87 +* Add support for all possible `erlang:decode_packet/3` responses, + previously these would just crash. + https://github.com/mochi/mochiweb/pull/114 +* Makefile fixed to make `make test` work before `make all` + https://github.com/mochi/mochiweb/pull/116 +* Usage of the crypto module made R16B01+ compatible + https://github.com/mochi/mochiweb/pull/115 +* Build fixed for R16B01 + https://github.com/mochi/mochiweb/pull/112 +* `mochiweb_socket_server:stop/1` is now a synchronous + call instead of an asynchronous cast +* `mochiweb_html:parse_tokens/1` (and `parse/1`) will now create a + html element to wrap documents that have a HTML5 doctype + (``) but no html element + https://github.com/mochi/mochiweb/issues/110 + +Version 2.6.0 released 2013-04-15 + +* Enable R15B gen_tcp workaround only on R15B + https://github.com/mochi/mochiweb/pull/107 + +Version 2.5.0 released 2013-03-04 + +* Replace now() with os:timestamp() in acceptor (optimization) + https://github.com/mochi/mochiweb/pull/102 +* New mochiweb_session module for managing session cookies. + NOTE: this module is only supported on R15B02 and later! + https://github.com/mochi/mochiweb/pull/94 +* New mochiweb_base64url module for base64url encoding + (URL and Filename safe alphabet, see RFC 4648). +* Fix rebar.config in mochiwebapp_skel to use {branch, "master"} + https://github.com/mochi/mochiweb/issues/105 + +Version 2.4.2 released 2013-02-05 + +* Fixed issue in mochiweb_response introduced in v2.4.0 + https://github.com/mochi/mochiweb/pull/100 + +Version 2.4.1 released 2013-01-30 + +* Fixed issue in mochiweb_request introduced in v2.4.0 + https://github.com/mochi/mochiweb/issues/97 +* Fixed issue in mochifmt_records introduced in v2.4.0 + https://github.com/mochi/mochiweb/issues/96 + +Version 2.4.0 released 2013-01-23 + +* Switch from parameterized modules to explicit tuple module calls for + R16 compatibility (#95) +* Fix for mochiweb_acceptor crash with extra-long HTTP headers under + R15B02 (#91) +* Fix case in handling range headers (#85) +* Handle combined Content-Length header (#88) +* Windows security fix for `safe_relative_path`, any path with a + backslash on any platform is now considered unsafe (#92) + +Version 2.3.2 released 2012-07-27 + +* Case insensitive match for "Connection: close" (#81) + +Version 2.3.1 released 2012-03-31 + +* Fix edoc warnings (#63) +* Fix mochiweb_html handling of invalid charref sequences (unescaped &) (#69). +* Add a manual garbage collection between requests to avoid worst case behavior + on keep-alive sockets. +* Fix dst cookie bug (#73) +* Removed unnecessary template_dir option, see + https://github.com/basho/rebar/issues/203 + +Version 2.3.0 released 2011-10-14 + +* Handle ssl_closed message in mochiweb_http (#59) +* Added support for new MIME types (otf, eot, m4v, svg, svgz, ttc, ttf, + vcf, webm, webp, woff) (#61) +* Updated mochiweb_charref to support all HTML5 entities. Note that + if you are using this module directly, the spec has changed to return + `[integer()]` for some entities. (#64) + +Version 2.2.1 released 2011-08-31 + +* Removed `mochiweb_skel` module from the pre-rebar era + +Version 2.2.0 released 2011-08-29 + +* Added new `mochiweb_http:start_link/1` and + `mochiweb_socket_server:start_link/1` APIs to explicitly start linked + servers. Also added `{link, false}` option to the `start/1` variants + to explicitly start unlinked. This is in expectation that we will + eventually change the default behavior of `start/1` to be unlinked as you + would expect it to. See https://github.com/mochi/mochiweb/issues/58 for + discussion. + +Version 2.1.0 released 2011-08-29 + +* Added new `mochijson2:decode/2` with `{format, struct | proplist | eep18}` + options for easy decoding to various proplist formats. Also added encoding + support for eep18 style objects. diff --git a/rabbitmq-server/deps/rabbit/LICENSE-MIT-Mochi b/deps/mochiweb/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbit/LICENSE-MIT-Mochi rename to deps/mochiweb/LICENSE diff --git a/deps/mochiweb/Makefile b/deps/mochiweb/Makefile new file mode 100644 index 0000000..244d7be --- /dev/null +++ b/deps/mochiweb/Makefile @@ -0,0 +1,22 @@ +IGNORE_DEPS += edown eper eunit_formatters meck node_package rebar_lock_deps_plugin rebar_vsn_plugin reltool_util +C_SRC_DIR = /path/do/not/exist +C_SRC_TYPE = rebar +DRV_CFLAGS = -fPIC +export DRV_CFLAGS +ERLANG_ARCH = 64 +export ERLANG_ARCH +ERLC_OPTS = +debug_info +export ERLC_OPTS + +COMPILE_FIRST += + + +rebar_dep: preprocess pre-deps deps pre-app app + +preprocess:: + +pre-deps:: + +pre-app:: + +include ../../erlang.mk \ No newline at end of file diff --git a/deps/mochiweb/Makefile.orig.mk b/deps/mochiweb/Makefile.orig.mk new file mode 100644 index 0000000..983c304 --- /dev/null +++ b/deps/mochiweb/Makefile.orig.mk @@ -0,0 +1,24 @@ +PREFIX:=../ +DEST:=$(PREFIX)$(PROJECT) + +REBAR=./rebar + +.PHONY: all edoc test clean build_plt dialyzer app + +all: + @$(REBAR) prepare-deps + +edoc: all + @$(REBAR) doc + +test: + @rm -rf .eunit + @mkdir -p .eunit + @$(REBAR) eunit + +clean: + @$(REBAR) clean + +app: + @[ -z "$(PROJECT)" ] && echo "ERROR: required variable PROJECT missing" 1>&2 && exit 1 || true + @$(REBAR) -r create template=mochiwebapp dest=$(DEST) appid=$(PROJECT) diff --git a/deps/mochiweb/README b/deps/mochiweb/README new file mode 100644 index 0000000..80ee6e4 --- /dev/null +++ b/deps/mochiweb/README @@ -0,0 +1,17 @@ +MochiWeb is an Erlang library for building lightweight HTTP servers. + +The latest version of MochiWeb is available at http://github.com/mochi/mochiweb + +The mailing list for MochiWeb is at http://groups.google.com/group/mochiweb/ + +R12B compatibility: +The master of MochiWeb is tested with R14A and later. A branch compatible +with R12B is maintained separately at http://github.com/lemenkov/mochiweb +The R12B branch of that repository is mirrored in the official repository +occasionally for convenience. + +To create a new mochiweb using project: + make app PROJECT=project_name + +To create a new mochiweb using project in a specific directory: + make app PROJECT=project_name PREFIX=$HOME/projects/ diff --git a/deps/mochiweb/examples/hmac_api/README b/deps/mochiweb/examples/hmac_api/README new file mode 100644 index 0000000..3771323 --- /dev/null +++ b/deps/mochiweb/examples/hmac_api/README @@ -0,0 +1,206 @@ +Introduction +------------ + +This example shows how to make an Amazon-style HMAC authentication system for an API with mochiweb. + +Purpose +------- + +The purpose of this example is to: +* make it easy to implement an API in mochiweb + - using a proven approach so that 'amateurs' don't have to reinvent crypto +* make it easy to generate client libraries for that API so that client-side implementers can: + - reuse closely related code examples + - build compatibility unit tests instead of fiddling around debugging their library against live implementations of the system + +Scope +----- + +The scope of this document is: +* a description of the client-server exchange +* a reference implementation of + - the server-side implementation of the exchange + - the client-side implementation of the exchange +* developing a custom implementation of an API +* deploying that implementation to new client-side users to build their client libraries + +Contents +-------- + +Subsequent sections of this document are: +* the client-server exchange +* the reference implementation in this example +* building a custom implementation +* deploying a custom implementation + +The Client-Server Exchange +-------------------------- + +OVERVIEW + +This section describes the client-server exchange for an Amazon-style API authentication schema. It has the following characteristics: +* based on a public key/private key +* used to authenticate non-SSL api requests +* not a full once-use schema and is vulnerable to replay attacks within a short time window + +TYPE OF API + +The api described in this document is: +* suitable for machine-machine communication + +The api described in this document is NOT: +* an implementation of 2-legged OAUTH + - see https://github.com/tim/erlang-oauth +* an implementation of 3-legged OAUTH + +It is not suitable for use in applications where an end user has to log into a service and piggy-back on top of a keypair security system. + +THE CLIENT LIBRARY HERE IS **NOT** AN AMAZON CLIENT LIBRARY. AMAZON DOES FUNKY STUFF WITH HOSTNAMES AND PUSHES THEM ONTO THE URL IN CANONICALIZATION! THE CLIENT LIBRARY IS AMAZON-A-LIKE ENOUGH TO USE THE AMAZON DOCOS TO BUILD A TEST SUITE. + +STEP 1 + +The client is issued with a pair of keys, one public, one private, for example: +* public: "bcaa49f2a4f7d4f92ac36c8bf66d5bb6" +* private: "92bc93d6b8aaec1cde772f903e06daf5" + +In the Amazon docs these are referred to as: +* AWSAccessKeyId (public) +* AWSSecretAccessKey (private) + +These can be generated by the function: +hmac_api_lib:get_api_keypair/0 + +This function returns cryptographically strong random numbers using the openSSL crypto library under the covers. + +The public key is used as a declaration of identity, "I am bcaa49..." + +The private key is never passed over the wire and is used to construct the same hash on both the client- and the server-side. + +STEP 2 + +The client prepares their request: +* url +* time of request +* action (GET, POST, etc) +* type of request (application/json, etc) +* contents of request +* etc, etc + +These components are then turned into a string called the canonical form. + +The HTTP protocol is permissive; it treats different requests as if they were the same. For instance it doesn't care about the order in which headers are sent, and allows the same header to contain multiple values as a list or be specified multiple times as a key-value pair. + +Intermediate machines between the client and server MAY pack and repack the HTTP request as long as they don't alter its meaning in a narrow sense. This means that the format of the HTTP request is not guaranteed to be maintained. + +The canonical form simply ensures that all the valid ways of making the same request are represented by the same string - irrespective of how this is done. + +The canonical form handles POST bodies and query parameters and silently discards anchors in URL's. + +A hash of this string is made with the private key. + +STEP 3 + +The client makes the request to the server: +* the signature is included in the request in the standard HTTPAuthorization header. (As the Amazon documentation points out this is infelicitous as it is being used for Authentication not Authorization, but hey!). + +The Authorization header constructed has the form: + + +An Amazon one looks like: +Authorization: AWS 0PN5J17HBGZHT7JJ3X82:frJIUN8DYpKDtOLCwo//yllqDzg= + --- -------------------- ---------------------------- + sch public key signature + +The HTTP request is made. + +STEP 4 + +The request is processed: +* the server receives the request +* the server constructs the canonical form from the attributes of the request: + - url + - date header + - action (GET, POST, etc) + - content type of request (application/json, etc) + - some custom headers + - etc, etc +* the server takes the client's public key from the HTTPAuthorization header and looks up the client's private key +* the server signs the canonical form with the private key +* the server compares: + - the signature in the request to the signature it has just generated + - the time encoded in the request with the server time +* the request is accepted or denied + +The time comparison is 'fuzzy'. Different server's clocks will be out of sync to a degree, the request may have acquired a time from an intermediate machine along the way, etc, etc. Normally a 'clock skew' time is allowed - in Amazon's case this is 15 minutes. + +NOTA BENE: THIS CLOCK SKEW TIME ALLOWS FOR REPLAY ATTACKS WHERE A BAD GUY SIMPLY CAPTURES AND REPLAYS TRAFFIC. + +EXTENSION + +It is possible to extend this schema to prevent replay attacks. The server issues a nonce token (a random string) which is included in the signature. When the server authorizes the request it stores the token and prevents any request with that token (ie a replay) being authorized again. + +The client receives its next nonce token in the response to a successful request. + +The Reference Implementation In This Example +-------------------------------------------- + +The reference implementation used in this example is that described in the Amazon documentation here: +http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html + +The try out the reference implementation: +* create a new mochiweb project as per the mochiweb README + - make app PROJECT=project_name +* copy hmac_api_lib.erl and hmac_api_client.erl into project_name/src +* copy hmac_api.hrl into project_name/include +* edit project_name_web.erl and add a call to hmac_api_lib:authorize_request/1 + +authorize/request/1 should be called in the loop of project_name_web.erl as per: + + loop(Req, DocRoot) -> + Auth = hmac_api_lib:authorize_request(Req), + io:format("Auth is ~p~n", [Auth]), + "/" ++ Path = Req:get(path), + ... + +When this is done you are ready to test the api: +* run 'make' in project_name/ to build the Erlang +* start the web server with 'start-dev.sh' in project_name/ (this will also open an Erlang shell to the Erlang VM) + +To test the api run this command in the Erlang shell: +* hmac_api_client:fire(). + +The reference implementation uses 5 constants defined in hmac_api.hrl. +* schema +* headerprefix +* dateheader +* publickey +* privatekey + +Building A Custom Implementation +-------------------------------- + +The simplest custom implementation is to simply take the existing code and change the values of the following constants: +* schema +* headerprefix +* dateheader + +If the API is to be used 'as is', please use the values which are commented out in hmac_api.hrl. This will make easier for software developers to work out which version of which client-side libraries they can use. + +Client libraries written in other languages than Erlang can reemployment the test suite in hmac_api_lib.erl. + +More sophisticated changes will involve changes to the canonicalization functions. + +Use of a generic schema should make reuse of client libraries easier across different platforms. + +If you develop an ‘as-is’ client-side library in another language please consider submitting its code to this example. + +Deploying A Custom Implementation +--------------------------------- + +When deploying a custom implementation, the server-side code should be released with unit tests so the client-side developer can easily build a robust client. + +In addition to that you will need to specify: +* description of how the API works: + - ie the acceptable methods and urls + - custom headers and their usage (if appropriate) + diff --git a/deps/mochiweb/examples/hmac_api/hmac_api.hrl b/deps/mochiweb/examples/hmac_api/hmac_api.hrl new file mode 100644 index 0000000..ddce280 --- /dev/null +++ b/deps/mochiweb/examples/hmac_api/hmac_api.hrl @@ -0,0 +1,43 @@ +-author("Hypernumbers Ltd "). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% %%% +%%% Reference values for testing against Amazon documents %%% +%%% %%% +%%% These need to be changed in production! %%% +%%% %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +-define(schema, "AWS"). +%% defines the prefix for headers to be included in the signature +-define(headerprefix, "x-amz-"). +%% defines the date header +-define(dateheader, "x-amz-date"). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% %%% +%%% Default values for defining a generic API %%% +%%% %%% +%%% Only change these if you alter the canonicalisation %%% +%%% %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%-define(schema, "MOCHIAPI"). +%%-define(headerprefix, "x-mochiapi-"). +%%-define(dateheader, "x-mochiapi-date"). + +%% a couple of keys for testing +%% these are taken from the document +%% % http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html +%% they are not valid keys! +-define(publickey, "0PN5J17HBGZHT7JJ3X82"). +-define(privatekey, "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o"). + + +-record(hmac_signature, + { + method, + contentmd5, + contenttype, + date, + headers, + resource + }). diff --git a/deps/mochiweb/examples/hmac_api/hmac_api_client.erl b/deps/mochiweb/examples/hmac_api/hmac_api_client.erl new file mode 100644 index 0000000..a38fa96 --- /dev/null +++ b/deps/mochiweb/examples/hmac_api/hmac_api_client.erl @@ -0,0 +1,34 @@ +-module(hmac_api_client). + +-export([ + fire/0 + ]). + +-include("hmac_api.hrl"). +-author("Hypernumbers Ltd "). + +fire() -> + URL = "http://127.0.0.1:8080/some/page/yeah/", + %% Dates SHOULD conform to Section 3.3 of RFC2616 + %% the examples from the RFC are: + %% Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 + %% Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 + %% Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format + + %% Dates can be conveniently generated using dh_date.erl + %% https://github.com/daleharvey/dh_date + %% which is largely compatible with + %% http://uk.php.net/date + + %% You MIGHT find it convenient to insist on times in UTC only + %% as it reduces the errors caused by summer time and other + %% conversion issues + Method = post, + Headers = [{"content-type", "application/json"}, + {"date", "Sun, 10 Jul 2011 05:07:19"}], + ContentType = "application/json", + Body = "blah", + HTTPAuthHeader = hmac_api_lib:sign(?privatekey, Method, URL, + Headers, ContentType), + httpc:request(Method, {URL, [HTTPAuthHeader | Headers], + ContentType, Body}, [], []). diff --git a/deps/mochiweb/examples/hmac_api/hmac_api_lib.erl b/deps/mochiweb/examples/hmac_api/hmac_api_lib.erl new file mode 100644 index 0000000..6d04954 --- /dev/null +++ b/deps/mochiweb/examples/hmac_api/hmac_api_lib.erl @@ -0,0 +1,435 @@ +-module(hmac_api_lib). + +-include("hmac_api.hrl"). +-include_lib("eunit/include/eunit.hrl"). + +-author("Hypernumbers Ltd "). + +%%% this library supports the hmac_sha api on both the client-side +%%% AND the server-side +%%% +%%% sign/5 is used client-side to sign a request +%%% - it returns an HTTPAuthorization header +%%% +%%% authorize_request/1 takes a mochiweb Request as an arguement +%%% and checks that the request matches the signature +%%% +%%% get_api_keypair/0 creates a pair of public/private keys +%%% +%%% THIS LIB DOESN'T IMPLEMENT THE AMAZON API IT ONLY IMPLEMENTS +%%% ENOUGH OF IT TO GENERATE A TEST SUITE. +%%% +%%% THE AMAZON API MUNGES HOSTNAME AND PATHS IN A CUSTOM WAY +%%% THIS IMPLEMENTATION DOESN'T +-export([ + authorize_request/1, + sign/5, + get_api_keypair/0 + ]). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% %%% +%%% API %%% +%%% %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +authorize_request(Req) -> + Method = Req:get(method), + Path = Req:get(path), + Headers = normalise(mochiweb_headers:to_list(Req:get(headers))), + ContentMD5 = get_header(Headers, "content-md5"), + ContentType = get_header(Headers, "content-type"), + Date = get_header(Headers, "date"), + IncAuth = get_header(Headers, "authorization"), + {_Schema, _PublicKey, _Sig} = breakout(IncAuth), + %% normally you would use the public key to look up the private key + PrivateKey = ?privatekey, + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = Path}, + Signed = sign_data(PrivateKey, Signature), + {_, AuthHeader} = make_HTTPAuth_header(Signed), + case AuthHeader of + IncAuth -> "match"; + _ -> "no_match" + end. + +sign(PrivateKey, Method, URL, Headers, ContentType) -> + Headers2 = normalise(Headers), + ContentMD5 = get_header(Headers2, "content-md5"), + Date = get_header(Headers2, "date"), + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + SignedSig = sign_data(PrivateKey, Signature), + make_HTTPAuth_header(SignedSig). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% %%% +%%% Internal Functions %%% +%%% %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +breakout(Header) -> + [Schema, Tail] = string:tokens(Header, " "), + [PublicKey, Signature] = string:tokens(Tail, ":"), + {Schema, PublicKey, Signature}. + +get_api_keypair() -> + Public = mochihex:to_hex(binary_to_list(crypto:strong_rand_bytes(16))), + Private = mochihex:to_hex(binary_to_list(crypto:strong_rand_bytes(16))), + {Public, Private}. + +make_HTTPAuth_header(Signature) -> + {"Authorization", ?schema ++ " " + ++ ?publickey ++ ":" ++ Signature}. + +make_signature_string(#hmac_signature{} = S) -> + Date = get_date(S#hmac_signature.headers, S#hmac_signature.date), + string:to_upper(atom_to_list(S#hmac_signature.method)) ++ "\n" + ++ S#hmac_signature.contentmd5 ++ "\n" + ++ S#hmac_signature.contenttype ++ "\n" + ++ Date ++ "\n" + ++ canonicalise_headers(S#hmac_signature.headers) + ++ canonicalise_resource(S#hmac_signature.resource). + +sign_data(PrivateKey, #hmac_signature{} = Signature) -> + Str = make_signature_string(Signature), + sign2(PrivateKey, Str). + +%% this fn is the entry point for a unit test which is why it is broken out... +%% if yer encryption and utf8 and base45 doo-dahs don't work then +%% yer Donald is well and truly Ducked so ye may as weel test it... +sign2(PrivateKey, Str) -> + Sign = xmerl_ucs:to_utf8(Str), + binary_to_list(base64:encode(crypto:sha_mac(PrivateKey, Sign))). + +canonicalise_headers([]) -> "\n"; +canonicalise_headers(List) when is_list(List) -> + List2 = [{string:to_lower(K), V} || {K, V} <- lists:sort(List)], + c_headers2(consolidate(List2, []), []). + +c_headers2([], Acc) -> string:join(Acc, "\n") ++ "\n"; +c_headers2([{?headerprefix ++ Rest, Key} | T], Acc) -> + Hd = string:strip(?headerprefix ++ Rest) ++ ":" ++ string:strip(Key), + c_headers2(T, [Hd | Acc]); +c_headers2([_H | T], Acc) -> c_headers2(T, Acc). + +consolidate([H | []], Acc) -> [H | Acc]; +consolidate([{H, K1}, {H, K2} | Rest], Acc) -> + consolidate([{H, join(K1, K2)} | Rest], Acc); +consolidate([{H1, K1}, {H2, K2} | Rest], Acc) -> + consolidate([{rectify(H2), rectify(K2)} | Rest], [{H1, K1} | Acc]). + +join(A, B) -> string:strip(A) ++ ";" ++ string:strip(B). + +%% removes line spacing as per RFC 2616 Section 4.2 +rectify(String) -> + Re = "[\x20* | \t*]+", + re:replace(String, Re, " ", [{return, list}, global]). + +canonicalise_resource("http://" ++ Rest) -> c_res2(Rest); +canonicalise_resource("https://" ++ Rest) -> c_res2(Rest); +canonicalise_resource(X) -> c_res3(X). + +c_res2(Rest) -> + N = string:str(Rest, "/"), + {_, Tail} = lists:split(N, Rest), + c_res3("/" ++ Tail). + +c_res3(Tail) -> + URL = case string:str(Tail, "#") of + 0 -> Tail; + N -> {U, _Anchor} = lists:split(N, Tail), + U + end, + U3 = case string:str(URL, "?") of + 0 -> URL; + N2 -> {U2, Q} = lists:split(N2, URL), + U2 ++ canonicalise_query(Q) + end, + string:to_lower(U3). + +canonicalise_query(List) -> + List1 = string:to_lower(List), + List2 = string:tokens(List1, "&"), + string:join(lists:sort(List2), "&"). + +%% if there's a header date take it and ditch the date +get_date([], Date) -> Date; +get_date([{K, _V} | T], Date) -> case string:to_lower(K) of + ?dateheader -> []; + _ -> get_date(T, Date) + end. + +normalise(List) -> norm2(List, []). + +norm2([], Acc) -> Acc; +norm2([{K, V} | T], Acc) when is_atom(K) -> + norm2(T, [{string:to_lower(atom_to_list(K)), V} | Acc]); +norm2([H | T], Acc) -> norm2(T, [H | Acc]). + +get_header(Headers, Type) -> + case lists:keyfind(Type, 1, Headers) of + false -> []; + {_K, V} -> V + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% %%% +%%% Unit Tests %%% +%%% %%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + % taken from Amazon docs +%% http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html +hash_test1(_) -> + Sig = "DELETE\n\n\n\nx-amz-date:Tue, 27 Mar 2007 21:20:26 +0000\n/johnsmith/photos/puppy.jpg", + Key = ?privatekey, + Hash = sign2(Key, Sig), + Expected = "k3nL7gH3+PadhTEVn5Ip83xlYzk=", + ?assertEqual(Expected, Hash). + +%% taken from Amazon docs +%% http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html +hash_test2(_) -> + Sig = "GET\n\n\nTue, 27 Mar 2007 19:44:46 +0000\n/johnsmith/?acl", + Key = "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o", + Hash = sign2(Key, Sig), + Expected = "thdUi9VAkzhkniLj96JIrOPGi0g=", + ?assertEqual(Expected, Hash). + +%% taken from Amazon docs +%% http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?RESTAuthentication.html +hash_test3(_) -> + Sig = "GET\n\n\nWed, 28 Mar 2007 01:49:49 +0000\n/dictionary/" + ++ "fran%C3%A7ais/pr%c3%a9f%c3%a8re", + Key = "uV3F3YluFJax1cknvbcGwgjvx4QpvB+leU8dUj2o", + Hash = sign2(Key, Sig), + Expected = "dxhSBHoI6eVSPcXJqEghlUzZMnY=", + ?assertEqual(Expected, Hash). + +signature_test1(_) -> + URL = "http://example.com:90/tongs/ya/bas", + Method = post, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "POST\n\n\nSun, 10 Jul 2011 05:07:19 UTC\n\n/tongs/ya/bas", + ?assertEqual(Expected, Sig). + +signature_test2(_) -> + URL = "http://example.com:90/tongs/ya/bas", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [{"x-amz-acl", "public-read"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\nx-amz-acl:public-read\n/tongs/ya/bas", + ?assertEqual(Expected, Sig). + +signature_test3(_) -> + URL = "http://example.com:90/tongs/ya/bas", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [{"x-amz-acl", "public-read"}, + {"yantze", "blast-off"}, + {"x-amz-doobie", "bongwater"}, + {"x-amz-acl", "public-write"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\nx-amz-acl:public-read;public-write\nx-amz-doobie:bongwater\n/tongs/ya/bas", + ?assertEqual(Expected, Sig). + +signature_test4(_) -> + URL = "http://example.com:90/tongs/ya/bas", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [{"x-amz-acl", "public-read"}, + {"yantze", "blast-off"}, + {"x-amz-doobie oobie \t boobie ", "bongwater"}, + {"x-amz-acl", "public-write"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\nx-amz-acl:public-read;public-write\nx-amz-doobie oobie boobie:bongwater\n/tongs/ya/bas", + ?assertEqual(Expected, Sig). + +signature_test5(_) -> + URL = "http://example.com:90/tongs/ya/bas", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [{"x-amz-acl", "public-Read"}, + {"yantze", "Blast-Off"}, + {"x-amz-doobie Oobie \t boobie ", "bongwater"}, + {"x-amz-acl", "public-write"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\nx-amz-acl:public-Read;public-write\nx-amz-doobie oobie boobie:bongwater\n/tongs/ya/bas", + ?assertEqual(Expected, Sig). + +signature_test6(_) -> + URL = "http://example.com:90/tongs/ya/bas/?andy&zbish=bash&bosh=burp", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\n\n" + ++ "/tongs/ya/bas/?andy&bosh=burp&zbish=bash", + ?assertEqual(Expected, Sig). + +signature_test7(_) -> + URL = "http://exAMPLE.Com:90/tONgs/ya/bas/?ANdy&ZBish=Bash&bOsh=burp", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\nSun, 10 Jul 2011 05:07:19 UTC\n\n" + ++"/tongs/ya/bas/?andy&bosh=burp&zbish=bash", + ?assertEqual(Expected, Sig). + +signature_test8(_) -> + URL = "http://exAMPLE.Com:90/tONgs/ya/bas/?ANdy&ZBish=Bash&bOsh=burp", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "", + Headers = [{"x-aMz-daTe", "Tue, 27 Mar 2007 21:20:26 +0000"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\n\n" + ++"x-amz-date:Tue, 27 Mar 2007 21:20:26 +0000\n" + ++"/tongs/ya/bas/?andy&bosh=burp&zbish=bash", + ?assertEqual(Expected, Sig). + +signature_test9(_) -> + URL = "http://exAMPLE.Com:90/tONgs/ya/bas/?ANdy&ZBish=Bash&bOsh=burp", + Method = get, + ContentMD5 = "", + ContentType = "", + Date = "Sun, 10 Jul 2011 05:07:19 UTC", + Headers = [{"x-amz-date", "Tue, 27 Mar 2007 21:20:26 +0000"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = make_signature_string(Signature), + Expected = "GET\n\n\n\n" + ++"x-amz-date:Tue, 27 Mar 2007 21:20:26 +0000\n" + ++"/tongs/ya/bas/?andy&bosh=burp&zbish=bash", + ?assertEqual(Expected, Sig). + +amazon_test1(_) -> + URL = "http://exAMPLE.Com:90/johnsmith/photos/puppy.jpg", + Method = delete, + ContentMD5 = "", + ContentType = "", + Date = "", + Headers = [{"x-amz-date", "Tue, 27 Mar 2007 21:20:26 +0000"}], + Signature = #hmac_signature{method = Method, + contentmd5 = ContentMD5, + contenttype = ContentType, + date = Date, + headers = Headers, + resource = URL}, + Sig = sign_data(?privatekey, Signature), + Expected = "k3nL7gH3+PadhTEVn5Ip83xlYzk=", + ?assertEqual(Expected, Sig). + +unit_test_() -> + Setup = fun() -> ok end, + Cleanup = fun(_) -> ok end, + + Series1 = [ + fun hash_test1/1, + fun hash_test2/1, + fun hash_test3/1 + ], + + Series2 = [ + fun signature_test1/1, + fun signature_test2/1, + fun signature_test3/1, + fun signature_test4/1, + fun signature_test5/1, + fun signature_test6/1, + fun signature_test7/1, + fun signature_test8/1, + fun signature_test9/1 + ], + + Series3 = [ + fun amazon_test1/1 + ], + + {setup, Setup, Cleanup, [ + {with, [], Series1}, + {with, [], Series2}, + {with, [], Series3} + ]}. diff --git a/deps/mochiweb/examples/https/https_store.erl b/deps/mochiweb/examples/https/https_store.erl new file mode 100644 index 0000000..959cc00 --- /dev/null +++ b/deps/mochiweb/examples/https/https_store.erl @@ -0,0 +1,146 @@ + +%% Trivial web storage app. It's available over both HTTP (port 8442) +%% and HTTPS (port 8443). You use a PUT to store items, a GET to +%% retrieve them and DELETE to delete them. The HTTP POST method is +%% invalid for this application. Example (using HTTPS transport): +%% +%% $ curl -k --verbose https://localhost:8443/flintstones +%% ... +%% 404 Not Found +%% ... +%% $ echo -e "Fred\nWilma\nBarney" | +%% curl -k --verbose https://localhost:8443/flintstones \ +%% -X PUT -H "Content-Type: text/plain" --data-binary @- +%% ... +%% 201 Created +%% ... +%% $ curl -k --verbose https://localhost:8443/flintstones +%% ... +%% Fred +%% Wilma +%% Barney +%% ... +%% $ curl -k --verbose https://localhost:8443/flintstones -X DELETE +%% ... +%% 200 OK +%% ... +%% $ curl -k --verbose https://localhost:8443/flintstones +%% ... +%% 404 Not Found +%% ... +%% +%% All submitted data is stored in memory (in an ets table). Could be +%% useful for ad-hoc testing. + +-module(https_store). + +-export([start/0, + stop/0, + dispatch/1, + loop/1 + ]). + +-define(HTTP_OPTS, [ + {loop, {?MODULE, dispatch}}, + {port, 8442}, + {name, http_8442} + ]). + +-define(HTTPS_OPTS, [ + {loop, {?MODULE, dispatch}}, + {port, 8443}, + {name, https_8443}, + {ssl, true}, + {ssl_opts, [ + {certfile, "server_cert.pem"}, + {keyfile, "server_key.pem"}]} + ]). + +-record(sd, {http, https}). +-record(resource, {type, data}). + +start() -> + {ok, Http} = mochiweb_http:start(?HTTP_OPTS), + {ok, Https} = mochiweb_http:start(?HTTPS_OPTS), + SD = #sd{http=Http, https=Https}, + Pid = spawn_link(fun() -> + ets:new(?MODULE, [named_table]), + loop(SD) + end), + register(http_store, Pid), + ok. + +stop() -> + http_store ! stop, + ok. + +dispatch(Req) -> + case Req:get(method) of + 'GET' -> + get_resource(Req); + 'PUT' -> + put_resource(Req); + 'DELETE' -> + delete_resource(Req); + _ -> + Headers = [{"Allow", "GET,PUT,DELETE"}], + Req:respond({405, Headers, "405 Method Not Allowed\r\n"}) + end. + +get_resource(Req) -> + Path = Req:get(path), + case ets:lookup(?MODULE, Path) of + [{Path, #resource{type=Type, data=Data}}] -> + Req:ok({Type, Data}); + [] -> + Req:respond({404, [], "404 Not Found\r\n"}) + end. + +put_resource(Req) -> + ContentType = case Req:get_header_value("Content-Type") of + undefined -> + "application/octet-stream"; + S -> + S + end, + Resource = #resource{type=ContentType, data=Req:recv_body()}, + http_store ! {self(), {put, Req:get(path), Resource}}, + Pid = whereis(http_store), + receive + {Pid, created} -> + Req:respond({201, [], "201 Created\r\n"}); + {Pid, updated} -> + Req:respond({200, [], "200 OK\r\n"}) + end. + +delete_resource(Req) -> + http_store ! {self(), {delete, Req:get(path)}}, + Pid = whereis(http_store), + receive + {Pid, ok} -> + Req:respond({200, [], "200 OK\r\n"}) + end. + +loop(#sd{http=Http, https=Https} = SD) -> + receive + stop -> + ok = mochiweb_http:stop(Http), + ok = mochiweb_http:stop(Https), + exit(normal); + {From, {put, Key, Val}} -> + Exists = ets:member(?MODULE, Key), + ets:insert(?MODULE, {Key, Val}), + case Exists of + true -> + From ! {self(), updated}; + false -> + From ! {self(), created} + end; + {From, {delete, Key}} -> + ets:delete(?MODULE, Key), + From ! {self(), ok}; + _ -> + ignore + end, + ?MODULE:loop(SD). + diff --git a/deps/mochiweb/examples/https/server_cert.pem b/deps/mochiweb/examples/https/server_cert.pem new file mode 100644 index 0000000..f84ccca --- /dev/null +++ b/deps/mochiweb/examples/https/server_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIJAJLkNZzERPIUMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV +BAMTCWxvY2FsaG9zdDAeFw0xMDAzMTgxOTM5MThaFw0yMDAzMTUxOTM5MThaMBQx +EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAJeUCOZxbmtngF4S5lXckjSDLc+8C+XjMBYBPyy5eKdJY20AQ1s9/hhp3ulI +8pAvl+xVo4wQ+iBSvOzcy248Q+Xi6+zjceF7UNRgoYPgtJjKhdwcHV3mvFFrS/fp +9ggoAChaJQWDO1OCfUgTWXImhkw+vcDR11OVMAJ/h73dqzJPI9mfq44PTTHfYtgr +v4LAQAOlhXIAa2B+a6PlF6sqDqJaW5jLTcERjsBwnRhUGi7JevQzkejujX/vdA+N +jRBjKH/KLU5h3Q7wUchvIez0PXWVTCnZjpA9aR4m7YV05nKQfxtGd71czYDYk+j8 +hd005jetT4ir7JkAWValBybJVksCAwEAAaN1MHMwHQYDVR0OBBYEFJl9s51SnjJt +V/wgKWqV5Q6jnv1ZMEQGA1UdIwQ9MDuAFJl9s51SnjJtV/wgKWqV5Q6jnv1ZoRik +FjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCS5DWcxETyFDAMBgNVHRMEBTADAQH/ +MA0GCSqGSIb3DQEBBQUAA4IBAQB2ldLeLCc+lxK5i0EZquLamMBJwDIjGpT0JMP9 +b4XQOK2JABIu54BQIZhwcjk3FDJz/uOW5vm8k1kYni8FCjNZAaRZzCUfiUYTbTKL +Rq9LuIAODyP2dnTqyKaQOOJHvrx9MRZ3XVecXPS0Tib4aO57vCaAbIkmhtYpTWmw +e3t8CAIDVtgvjR6Se0a1JA4LktR7hBu22tDImvCSJn1nVAaHpani6iPBPPdMuMsP +TBoeQfj8VpqBUjCStqJGa8ytjDFX73YaxV2mgrtGwPNme1x3YNRR11yTu7tksyMO +GrmgxNriqYRchBhNEf72AKF0LR1ByKwfbDB9rIsV00HtCgOp +-----END CERTIFICATE----- diff --git a/deps/mochiweb/examples/https/server_key.pem b/deps/mochiweb/examples/https/server_key.pem new file mode 100644 index 0000000..69bbf82 --- /dev/null +++ b/deps/mochiweb/examples/https/server_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAl5QI5nFua2eAXhLmVdySNIMtz7wL5eMwFgE/LLl4p0ljbQBD +Wz3+GGne6UjykC+X7FWjjBD6IFK87NzLbjxD5eLr7ONx4XtQ1GChg+C0mMqF3Bwd +Xea8UWtL9+n2CCgAKFolBYM7U4J9SBNZciaGTD69wNHXU5UwAn+Hvd2rMk8j2Z+r +jg9NMd9i2Cu/gsBAA6WFcgBrYH5ro+UXqyoOolpbmMtNwRGOwHCdGFQaLsl69DOR +6O6Nf+90D42NEGMof8otTmHdDvBRyG8h7PQ9dZVMKdmOkD1pHibthXTmcpB/G0Z3 +vVzNgNiT6PyF3TTmN61PiKvsmQBZVqUHJslWSwIDAQABAoIBACI8Ky5xHDFh9RpK +Rn/KC7OUlTpADKflgizWJ0Cgu2F9L9mkn5HyFHvLHa+u7CootbWJOiEejH/UcBtH +WyMQtX0snYCpdkUpJv5wvMoebGu+AjHOn8tfm9T/2O6rhwgckLyMb6QpGbMo28b1 +p9QiY17BJPZx7qJQJcHKsAvwDwSThlb7MFmWf42LYWlzybpeYQvwpd+UY4I0WXLu +/dqJIS9Npq+5Y5vbo2kAEAssb2hSCvhCfHmwFdKmBzlvgOn4qxgZ1iHQgfKI6Z3Y +J0573ZgOVTuacn+lewtdg5AaHFcl/zIYEr9SNqRoPNGbPliuv6k6N2EYcufWL5lR +sCmmmHECgYEAxm+7OpepGr++K3+O1e1MUhD7vSPkKJrCzNtUxbOi2NWj3FFUSPRU +adWhuxvUnZgTcgM1+KuQ0fB2VmxXe9IDcrSFS7PKFGtd2kMs/5mBw4UgDZkOQh+q +kDiBEV3HYYJWRq0w3NQ/9Iy1jxxdENHtGmG9aqamHxNtuO608wGW2S8CgYEAw4yG +ZyAic0Q/U9V2OHI0MLxLCzuQz17C2wRT1+hBywNZuil5YeTuIt2I46jro6mJmWI2 +fH4S/geSZzg2RNOIZ28+aK79ab2jWBmMnvFCvaru+odAuser4N9pfAlHZvY0pT+S +1zYX3f44ygiio+oosabLC5nWI0zB2gG8pwaJlaUCgYEAgr7poRB+ZlaCCY0RYtjo +mYYBKD02vp5BzdKSB3V1zeLuBWM84pjB6b3Nw0fyDig+X7fH3uHEGN+USRs3hSj6 +BqD01s1OT6fyfbYXNw5A1r+nP+5h26Wbr0zblcKxdQj4qbbBZC8hOJNhqTqqA0Qe +MmzF7jiBaiZV/Cyj4x1f9BcCgYEAhjL6SeuTuOctTqs/5pz5lDikh6DpUGcH8qaV +o6aRAHHcMhYkZzpk8yh1uUdD7516APmVyvn6rrsjjhLVq4ZAJjwB6HWvE9JBN0TR +bILF+sREHUqU8Zn2Ku0nxyfXCKIOnxlx/J/y4TaGYqBqfXNFWiXNUrjQbIlQv/xR +K48g/MECgYBZdQlYbMSDmfPCC5cxkdjrkmAl0EgV051PWAi4wR+hLxIMRjHBvAk7 +IweobkFvT4TICulgroLkYcSa5eOZGxB/DHqcQCbWj3reFV0VpzmTDoFKG54sqBRl +vVntGt0pfA40fF17VoS7riAdHF53ippTtsovHEsg5tq5NrBl5uKm2g== +-----END RSA PRIVATE KEY----- diff --git a/deps/mochiweb/examples/keepalive/keepalive.erl b/deps/mochiweb/examples/keepalive/keepalive.erl new file mode 100644 index 0000000..965a17e --- /dev/null +++ b/deps/mochiweb/examples/keepalive/keepalive.erl @@ -0,0 +1,81 @@ +-module(keepalive). + +%% your web app can push data to clients using a technique called comet long +%% polling. browsers make a request and your server waits to send a +%% response until data is available. see wikipedia for a better explanation: +%% http://en.wikipedia.org/wiki/Comet_(programming)#Ajax_with_long_polling +%% +%% since the majority of your http handlers will be idle at any given moment, +%% you might consider making them hibernate while they wait for more data from +%% another process. however, since the execution stack is discarded when a +%% process hibernates, the handler would usually terminate after your response +%% code runs. this means http keep alives wouldn't work; the handler process +%% would terminate after each response and close its socket rather than +%% returning to the big @mochiweb_http@ loop and processing another request. +%% +%% however, if mochiweb exposes a continuation that encapsulates the return to +%% the top of the big loop in @mochiweb_http@, we can call that after the +%% response. if you do that then control flow returns to the proper place, +%% and keep alives work like they would if you hadn't hibernated. + +-export([ start/1, loop/1 + ]). + +%% internal export (so hibernate can reach it) +-export([ resume/3 + ]). + +-define(LOOP, {?MODULE, loop}). + +start(Options = [{port, _Port}]) -> + mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP} | Options]). + +loop(Req) -> + Path = Req:get(path), + case string:tokens(Path, "/") of + ["longpoll" | RestOfPath] -> + %% the "reentry" is a continuation -- what @mochiweb_http@ + %% needs to do to start its loop back at the top + Reentry = mochiweb_http:reentry(?LOOP), + + %% here we could send a message to some other process and hope + %% to get an interesting message back after a while. for + %% simplicity let's just send ourselves a message after a few + %% seconds + erlang:send_after(2000, self(), "honk honk"), + + %% since we expect to wait for a long time before getting a + %% reply, let's hibernate. memory usage will be minimized, so + %% we won't be wasting memory just sitting in a @receive@ + proc_lib:hibernate(?MODULE, resume, [Req, RestOfPath, Reentry]), + + %% we'll never reach this point, and this function @loop/1@ + %% won't ever return control to @mochiweb_http@. luckily + %% @resume/3@ will take care of that. + io:format("not gonna happen~n", []); + + _ -> + ok(Req, io_lib:format("some other page: ~p", [Path])) + end, + + io:format("restarting loop normally in ~p~n", [Path]), + ok. + +%% this is the function that's called when a message arrives. +resume(Req, RestOfPath, Reentry) -> + receive + Msg -> + Text = io_lib:format("wake up message: ~p~nrest of path: ~p", [Msg, RestOfPath]), + ok(Req, Text) + end, + + %% if we didn't call @Reentry@ here then the function would finish and the + %% process would exit. calling @Reentry@ takes care of returning control + %% to @mochiweb_http@ + io:format("reentering loop via continuation in ~p~n", [Req:get(path)]), + Reentry(Req). + +ok(Req, Response) -> + Req:ok({_ContentType = "text/plain", + _Headers = [], + Response}). diff --git a/deps/mochiweb/examples/websocket/index.html b/deps/mochiweb/examples/websocket/index.html new file mode 100644 index 0000000..6926aba --- /dev/null +++ b/deps/mochiweb/examples/websocket/index.html @@ -0,0 +1,59 @@ + + + + Websockets With Mochiweb Demo + + +

Mochiweb websocket demo

+ +
+ +   State: +
+
Protip: open your javascript error console, just in case..
+
+
+
+ + +
+
+
+
+ + + + + diff --git a/deps/mochiweb/examples/websocket/websocket.erl b/deps/mochiweb/examples/websocket/websocket.erl new file mode 100644 index 0000000..cd52da1 --- /dev/null +++ b/deps/mochiweb/examples/websocket/websocket.erl @@ -0,0 +1,148 @@ +-module(websocket). + +%% To run: erlc websocket.erl && erl -pa ../../ebin -s websocket + +%% The MIT License (MIT) + +%% Copyright (c) 2012 Zadane.pl sp. z o.o. + +%% 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. + +-export([start/0, start_link/0, ws_loop/3, loop/2]). +-export([broadcast_server/1]). + +%% +%% Mochiweb websocket example +%% +%% [1]: At first you have to start HTTP server which will listen for HTTP +%% requests and eventually upgrade connection to websocket +%% [2]: Attempt to upgrade connection to websocket. +%% Function mochiweb_websocket:upgrade_connection/2: +%% * first argument is mochiweb_request +%% * second is M:F which will handle further websocket messages. +%% Function return two funs: +%% * ReentryWs/1 - use it to enter to messages handling loop +%% (in this example ws_loop/3) +%% * ReplyChannel/1 - use to send messages to client. May be passed to +%% other processes +%% [3]: Example of sending message to client +%% [4]: State that will be passed to message handling loop +%% [5]: Pass control to messages handling loop. From this moment each message +%% received from client can be handled... +%% [6]: ...here as Payload. State is variable intended for holding your custom +%% state. ReplyChannel is the same function as in [3]. +%% Notice! Payload is list of messages received from client. Websocket +%% framing mechanism concatenates messages which are sent one after another +%% in short time. +%% [7]: Print payload received from client and send it back +%% [8]: Message handling function must return new state value +start() -> + spawn( + fun () -> + application:start(sasl), + start_link(), + receive + stop -> ok + end + end). + +start_link() -> + %% [1] + io:format("Listening at http://127.0.0.1:8080/~n"), + Broadcaster = spawn_link(?MODULE, broadcast_server, [dict:new()]), + mochiweb_http:start_link([ + {name, client_access}, + {loop, {?MODULE, loop, [Broadcaster]}}, + {port, 8080} + ]). + +ws_loop(Payload, Broadcaster, _ReplyChannel) -> + %% [6] + + %% [7] + io:format("Received data: ~p~n", [Payload]), + Received = list_to_binary(Payload), + Broadcaster ! {broadcast, self(), Received}, + + %% [8] + Broadcaster. + +loop(Req, Broadcaster) -> + H = mochiweb_request:get_header_value("Upgrade", Req), + loop(Req, + Broadcaster, + H =/= undefined andalso string:to_lower(H) =:= "websocket"). + +loop(Req, _Broadcaster, false) -> + mochiweb_request:serve_file("index.html", "./", Req); +loop(Req, Broadcaster, true) -> + {ReentryWs, ReplyChannel} = mochiweb_websocket:upgrade_connection( + Req, fun ?MODULE:ws_loop/3), + %% [3] + Broadcaster ! {register, self(), ReplyChannel}, + %% [4] + %% [5] + ReentryWs(Broadcaster). + + +%% This server keeps track of connected pids +broadcast_server(Pids) -> + Pids1 = receive + {register, Pid, Channel} -> + broadcast_register(Pid, Channel, Pids); + {broadcast, Pid, Message} -> + broadcast_sendall(Pid, Message, Pids); + {'DOWN', MRef, process, Pid, _Reason} -> + broadcast_down(Pid, MRef, Pids); + Msg -> + io:format("Unknown message: ~p~n", [Msg]), + Pids + end, + erlang:hibernate(?MODULE, broadcast_server, [Pids1]). + +broadcast_register(Pid, Channel, Pids) -> + MRef = erlang:monitor(process, Pid), + broadcast_sendall( + Pid, "connected", dict:store(Pid, {Channel, MRef}, Pids)). + +broadcast_down(Pid, MRef, Pids) -> + Pids1 = case dict:find(Pid, Pids) of + {ok, {_, MRef}} -> + dict:erase(Pid, Pids); + _ -> + Pids + end, + broadcast_sendall(Pid, "disconnected", Pids1). + +broadcast_sendall(Pid, Msg, Pids) -> + M = iolist_to_binary([pid_to_list(Pid), ": ", Msg]), + dict:fold( + fun (K, {Reply, MRef}, Acc) -> + try + begin + Reply(M), + dict:store(K, {Reply, MRef}, Acc) + end + catch + _:_ -> + Acc + end + end, + dict:new(), + Pids). diff --git a/deps/mochiweb/include/internal.hrl b/deps/mochiweb/include/internal.hrl new file mode 100644 index 0000000..6db899a --- /dev/null +++ b/deps/mochiweb/include/internal.hrl @@ -0,0 +1,3 @@ + +-define(RECBUF_SIZE, 8192). + diff --git a/deps/mochiweb/rebar b/deps/mochiweb/rebar new file mode 100755 index 0000000000000000000000000000000000000000..0d1980bf285e509ba967420330b4599c7bca2cee GIT binary patch literal 159782 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 + application:start(inets), + code:add_patha("ebin"), + {ok, {_, _, HTML}} = httpc:request("http://www.w3.org/TR/html5/named-character-references.html"), + print(lists:sort(search(mochiweb_html:parse(HTML)))). + +print([F | T]) -> + io:put_chars([clause(F), ";\n"]), + print(T); +print([]) -> + io:put_chars(["entity(_) -> undefined.\n"]), + ok. + +clause({Title, [Codepoint]}) -> + ["entity(\"", Title, "\") -> 16#", Codepoint]; +clause({Title, [First | Rest]}) -> + ["entity(\"", Title, "\") -> [16#", First, + [[", 16#", Codepoint] || Codepoint <- Rest], + "]"]. + + +search(Elem) -> + search(Elem, []). + +search({<<"tr">>, [{<<"id">>, <<"entity-", _/binary>>} | _], Children}, Acc) -> + %% HTML5 charrefs can have more than one code point(!) + [{<<"td">>, _, [{<<"code">>, _, [TitleSemi]}]}, + {<<"td">>, [], [RawCPs]} | _] = Children, + L = byte_size(TitleSemi) - 1, + <> = TitleSemi, + {match, Matches} = re:run(RawCPs, "(?:\\s*U\\+)([a-fA-F0-9]+)", + [{capture, all, binary}, global]), + [{Title, [CP || [_, CP] <- Matches]} | Acc]; +search({Tag, Attrs, [H | T]}, Acc) -> + search({Tag, Attrs, T}, search(H, Acc)); +search({_Tag, _Attrs, []}, Acc) -> + Acc; +search(<<_/binary>>, Acc) -> + Acc. diff --git a/deps/mochiweb/src/mochifmt.erl b/deps/mochiweb/src/mochifmt.erl new file mode 100644 index 0000000..6381bb7 --- /dev/null +++ b/deps/mochiweb/src/mochifmt.erl @@ -0,0 +1,443 @@ +%% @author Bob Ippolito +%% @copyright 2008 Mochi Media, Inc. +%% +%% 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. + +%% @doc String Formatting for Erlang, inspired by Python 2.6 +%% (PEP 3101). +%% +-module(mochifmt). +-author('bob@mochimedia.com'). +-export([format/2, format_field/2, convert_field/2, get_value/2, get_field/2]). +-export([tokenize/1, format/3, get_field/3, format_field/3]). +-export([bformat/2, bformat/3]). +-export([f/2, f/3]). + +-record(conversion, {length, precision, ctype, align, fill_char, sign}). + +%% @spec tokenize(S::string()) -> tokens() +%% @doc Tokenize a format string into mochifmt's internal format. +tokenize(S) -> + {?MODULE, tokenize(S, "", [])}. + +%% @spec convert_field(Arg, Conversion::conversion()) -> term() +%% @doc Process Arg according to the given explicit conversion specifier. +convert_field(Arg, "") -> + Arg; +convert_field(Arg, "r") -> + repr(Arg); +convert_field(Arg, "s") -> + str(Arg). + +%% @spec get_value(Key::string(), Args::args()) -> term() +%% @doc Get the Key from Args. If Args is a tuple then convert Key to +%% an integer and get element(1 + Key, Args). If Args is a list and Key +%% can be parsed as an integer then use lists:nth(1 + Key, Args), +%% otherwise try and look for Key in Args as a proplist, converting +%% Key to an atom or binary if necessary. +get_value(Key, Args) when is_tuple(Args) -> + element(1 + list_to_integer(Key), Args); +get_value(Key, Args) when is_list(Args) -> + try lists:nth(1 + list_to_integer(Key), Args) + catch error:_ -> + {_K, V} = proplist_lookup(Key, Args), + V + end. + +%% @spec get_field(Key::string(), Args) -> term() +%% @doc Consecutively call get_value/2 on parts of Key delimited by ".", +%% replacing Args with the result of the previous get_value. This +%% is used to implement formats such as {0.0}. +get_field(Key, Args) -> + get_field(Key, Args, ?MODULE). + +%% @spec get_field(Key::string(), Args, Module) -> term() +%% @doc Consecutively call Module:get_value/2 on parts of Key delimited by ".", +%% replacing Args with the result of the previous get_value. This +%% is used to implement formats such as {0.0}. +get_field(Key, Args, Module) -> + {Name, Next} = lists:splitwith(fun (C) -> C =/= $. end, Key), + Res = try Module:get_value(Name, Args) + catch error:undef -> get_value(Name, Args) end, + case Next of + "" -> + Res; + "." ++ S1 -> + get_field(S1, Res, Module) + end. + +%% @spec format(Format::string(), Args) -> iolist() +%% @doc Format Args with Format. +format(Format, Args) -> + format(Format, Args, ?MODULE). + +%% @spec format(Format::string(), Args, Module) -> iolist() +%% @doc Format Args with Format using Module. +format({?MODULE, Parts}, Args, Module) -> + format2(Parts, Args, Module, []); +format(S, Args, Module) -> + format(tokenize(S), Args, Module). + +%% @spec format_field(Arg, Format) -> iolist() +%% @doc Format Arg with Format. +format_field(Arg, Format) -> + format_field(Arg, Format, ?MODULE). + +%% @spec format_field(Arg, Format, _Module) -> iolist() +%% @doc Format Arg with Format. +format_field(Arg, Format, _Module) -> + F = default_ctype(Arg, parse_std_conversion(Format)), + fix_padding(fix_sign(convert2(Arg, F), F), F). + +%% @spec f(Format::string(), Args) -> string() +%% @doc Format Args with Format and return a string(). +f(Format, Args) -> + f(Format, Args, ?MODULE). + +%% @spec f(Format::string(), Args, Module) -> string() +%% @doc Format Args with Format using Module and return a string(). +f(Format, Args, Module) -> + case lists:member(${, Format) of + true -> + binary_to_list(bformat(Format, Args, Module)); + false -> + Format + end. + +%% @spec bformat(Format::string(), Args) -> binary() +%% @doc Format Args with Format and return a binary(). +bformat(Format, Args) -> + iolist_to_binary(format(Format, Args)). + +%% @spec bformat(Format::string(), Args, Module) -> binary() +%% @doc Format Args with Format using Module and return a binary(). +bformat(Format, Args, Module) -> + iolist_to_binary(format(Format, Args, Module)). + +%% Internal API + +add_raw("", Acc) -> + Acc; +add_raw(S, Acc) -> + [{raw, lists:reverse(S)} | Acc]. + +tokenize([], S, Acc) -> + lists:reverse(add_raw(S, Acc)); +tokenize("{{" ++ Rest, S, Acc) -> + tokenize(Rest, "{" ++ S, Acc); +tokenize("{" ++ Rest, S, Acc) -> + {Format, Rest1} = tokenize_format(Rest), + tokenize(Rest1, "", [{format, make_format(Format)} | add_raw(S, Acc)]); +tokenize("}}" ++ Rest, S, Acc) -> + tokenize(Rest, "}" ++ S, Acc); +tokenize([C | Rest], S, Acc) -> + tokenize(Rest, [C | S], Acc). + +tokenize_format(S) -> + tokenize_format(S, 1, []). + +tokenize_format("}" ++ Rest, 1, Acc) -> + {lists:reverse(Acc), Rest}; +tokenize_format("}" ++ Rest, N, Acc) -> + tokenize_format(Rest, N - 1, "}" ++ Acc); +tokenize_format("{" ++ Rest, N, Acc) -> + tokenize_format(Rest, 1 + N, "{" ++ Acc); +tokenize_format([C | Rest], N, Acc) -> + tokenize_format(Rest, N, [C | Acc]). + +make_format(S) -> + {Name0, Spec} = case lists:splitwith(fun (C) -> C =/= $: end, S) of + {_, ""} -> + {S, ""}; + {SN, ":" ++ SS} -> + {SN, SS} + end, + {Name, Transform} = case lists:splitwith(fun (C) -> C =/= $! end, Name0) of + {_, ""} -> + {Name0, ""}; + {TN, "!" ++ TT} -> + {TN, TT} + end, + {Name, Transform, Spec}. + +proplist_lookup(S, P) -> + A = try list_to_existing_atom(S) + catch error:_ -> make_ref() end, + B = try list_to_binary(S) + catch error:_ -> make_ref() end, + proplist_lookup2({S, A, B}, P). + +proplist_lookup2({KS, KA, KB}, [{K, V} | _]) + when KS =:= K orelse KA =:= K orelse KB =:= K -> + {K, V}; +proplist_lookup2(Keys, [_ | Rest]) -> + proplist_lookup2(Keys, Rest). + +format2([], _Args, _Module, Acc) -> + lists:reverse(Acc); +format2([{raw, S} | Rest], Args, Module, Acc) -> + format2(Rest, Args, Module, [S | Acc]); +format2([{format, {Key, Convert, Format0}} | Rest], Args, Module, Acc) -> + Format = f(Format0, Args, Module), + V = case Module of + ?MODULE -> + V0 = get_field(Key, Args), + V1 = convert_field(V0, Convert), + format_field(V1, Format); + _ -> + V0 = try Module:get_field(Key, Args) + catch error:undef -> get_field(Key, Args, Module) end, + V1 = try Module:convert_field(V0, Convert) + catch error:undef -> convert_field(V0, Convert) end, + try Module:format_field(V1, Format) + catch error:undef -> format_field(V1, Format, Module) end + end, + format2(Rest, Args, Module, [V | Acc]). + +default_ctype(_Arg, C=#conversion{ctype=N}) when N =/= undefined -> + C; +default_ctype(Arg, C) when is_integer(Arg) -> + C#conversion{ctype=decimal}; +default_ctype(Arg, C) when is_float(Arg) -> + C#conversion{ctype=general}; +default_ctype(_Arg, C) -> + C#conversion{ctype=string}. + +fix_padding(Arg, #conversion{length=undefined}) -> + Arg; +fix_padding(Arg, F=#conversion{length=Length, fill_char=Fill0, align=Align0, + ctype=Type}) -> + Padding = Length - iolist_size(Arg), + Fill = case Fill0 of + undefined -> + $\s; + _ -> + Fill0 + end, + Align = case Align0 of + undefined -> + case Type of + string -> + left; + _ -> + right + end; + _ -> + Align0 + end, + case Padding > 0 of + true -> + do_padding(Arg, Padding, Fill, Align, F); + false -> + Arg + end. + +do_padding(Arg, Padding, Fill, right, _F) -> + [lists:duplicate(Padding, Fill), Arg]; +do_padding(Arg, Padding, Fill, center, _F) -> + LPadding = lists:duplicate(Padding div 2, Fill), + RPadding = case Padding band 1 of + 1 -> + [Fill | LPadding]; + _ -> + LPadding + end, + [LPadding, Arg, RPadding]; +do_padding([$- | Arg], Padding, Fill, sign_right, _F) -> + [[$- | lists:duplicate(Padding, Fill)], Arg]; +do_padding(Arg, Padding, Fill, sign_right, #conversion{sign=$-}) -> + [lists:duplicate(Padding, Fill), Arg]; +do_padding([S | Arg], Padding, Fill, sign_right, #conversion{sign=S}) -> + [[S | lists:duplicate(Padding, Fill)], Arg]; +do_padding(Arg, Padding, Fill, sign_right, #conversion{sign=undefined}) -> + [lists:duplicate(Padding, Fill), Arg]; +do_padding(Arg, Padding, Fill, left, _F) -> + [Arg | lists:duplicate(Padding, Fill)]. + +fix_sign(Arg, #conversion{sign=$+}) when Arg >= 0 -> + [$+, Arg]; +fix_sign(Arg, #conversion{sign=$\s}) when Arg >= 0 -> + [$\s, Arg]; +fix_sign(Arg, _F) -> + Arg. + +ctype($\%) -> percent; +ctype($s) -> string; +ctype($b) -> bin; +ctype($o) -> oct; +ctype($X) -> upper_hex; +ctype($x) -> hex; +ctype($c) -> char; +ctype($d) -> decimal; +ctype($g) -> general; +ctype($f) -> fixed; +ctype($e) -> exp. + +align($<) -> left; +align($>) -> right; +align($^) -> center; +align($=) -> sign_right. + +convert2(Arg, F=#conversion{ctype=percent}) -> + [convert2(100.0 * Arg, F#conversion{ctype=fixed}), $\%]; +convert2(Arg, #conversion{ctype=string}) -> + str(Arg); +convert2(Arg, #conversion{ctype=bin}) -> + erlang:integer_to_list(Arg, 2); +convert2(Arg, #conversion{ctype=oct}) -> + erlang:integer_to_list(Arg, 8); +convert2(Arg, #conversion{ctype=upper_hex}) -> + erlang:integer_to_list(Arg, 16); +convert2(Arg, #conversion{ctype=hex}) -> + string:to_lower(erlang:integer_to_list(Arg, 16)); +convert2(Arg, #conversion{ctype=char}) when Arg < 16#80 -> + [Arg]; +convert2(Arg, #conversion{ctype=char}) -> + xmerl_ucs:to_utf8(Arg); +convert2(Arg, #conversion{ctype=decimal}) -> + integer_to_list(Arg); +convert2(Arg, #conversion{ctype=general, precision=undefined}) -> + try mochinum:digits(Arg) + catch error:undef -> io_lib:format("~g", [Arg]) end; +convert2(Arg, #conversion{ctype=fixed, precision=undefined}) -> + io_lib:format("~f", [Arg]); +convert2(Arg, #conversion{ctype=exp, precision=undefined}) -> + io_lib:format("~e", [Arg]); +convert2(Arg, #conversion{ctype=general, precision=P}) -> + io_lib:format("~." ++ integer_to_list(P) ++ "g", [Arg]); +convert2(Arg, #conversion{ctype=fixed, precision=P}) -> + io_lib:format("~." ++ integer_to_list(P) ++ "f", [Arg]); +convert2(Arg, #conversion{ctype=exp, precision=P}) -> + io_lib:format("~." ++ integer_to_list(P) ++ "e", [Arg]). + +str(A) when is_atom(A) -> + atom_to_list(A); +str(I) when is_integer(I) -> + integer_to_list(I); +str(F) when is_float(F) -> + try mochinum:digits(F) + catch error:undef -> io_lib:format("~g", [F]) end; +str(L) when is_list(L) -> + L; +str(B) when is_binary(B) -> + B; +str(P) -> + repr(P). + +repr(P) when is_float(P) -> + try mochinum:digits(P) + catch error:undef -> float_to_list(P) end; +repr(P) -> + io_lib:format("~p", [P]). + +parse_std_conversion(S) -> + parse_std_conversion(S, #conversion{}). + +parse_std_conversion("", Acc) -> + Acc; +parse_std_conversion([Fill, Align | Spec], Acc) + when Align =:= $< orelse Align =:= $> orelse Align =:= $= orelse Align =:= $^ -> + parse_std_conversion(Spec, Acc#conversion{fill_char=Fill, + align=align(Align)}); +parse_std_conversion([Align | Spec], Acc) + when Align =:= $< orelse Align =:= $> orelse Align =:= $= orelse Align =:= $^ -> + parse_std_conversion(Spec, Acc#conversion{align=align(Align)}); +parse_std_conversion([Sign | Spec], Acc) + when Sign =:= $+ orelse Sign =:= $- orelse Sign =:= $\s -> + parse_std_conversion(Spec, Acc#conversion{sign=Sign}); +parse_std_conversion("0" ++ Spec, Acc) -> + Align = case Acc#conversion.align of + undefined -> + sign_right; + A -> + A + end, + parse_std_conversion(Spec, Acc#conversion{fill_char=$0, align=Align}); +parse_std_conversion(Spec=[D|_], Acc) when D >= $0 andalso D =< $9 -> + {W, Spec1} = lists:splitwith(fun (C) -> C >= $0 andalso C =< $9 end, Spec), + parse_std_conversion(Spec1, Acc#conversion{length=list_to_integer(W)}); +parse_std_conversion([$. | Spec], Acc) -> + case lists:splitwith(fun (C) -> C >= $0 andalso C =< $9 end, Spec) of + {"", Spec1} -> + parse_std_conversion(Spec1, Acc); + {P, Spec1} -> + parse_std_conversion(Spec1, + Acc#conversion{precision=list_to_integer(P)}) + end; +parse_std_conversion([Type], Acc) -> + parse_std_conversion("", Acc#conversion{ctype=ctype(Type)}). + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +tokenize_test() -> + {?MODULE, [{raw, "ABC"}]} = tokenize("ABC"), + {?MODULE, [{format, {"0", "", ""}}]} = tokenize("{0}"), + {?MODULE, [{raw, "ABC"}, {format, {"1", "", ""}}, {raw, "DEF"}]} = + tokenize("ABC{1}DEF"), + ok. + +format_test() -> + <<" -4">> = bformat("{0:4}", [-4]), + <<" 4">> = bformat("{0:4}", [4]), + <<" 4">> = bformat("{0:{0}}", [4]), + <<"4 ">> = bformat("{0:4}", ["4"]), + <<"4 ">> = bformat("{0:{0}}", ["4"]), + <<"1.2yoDEF">> = bformat("{2}{0}{1}{3}", {yo, "DE", 1.2, <<"F">>}), + <<"cafebabe">> = bformat("{0:x}", {16#cafebabe}), + <<"CAFEBABE">> = bformat("{0:X}", {16#cafebabe}), + <<"CAFEBABE">> = bformat("{0:X}", {16#cafebabe}), + <<"755">> = bformat("{0:o}", {8#755}), + <<"a">> = bformat("{0:c}", {97}), + %% Horizontal ellipsis + <<226, 128, 166>> = bformat("{0:c}", {16#2026}), + <<"11">> = bformat("{0:b}", {3}), + <<"11">> = bformat("{0:b}", [3]), + <<"11">> = bformat("{three:b}", [{three, 3}]), + <<"11">> = bformat("{three:b}", [{"three", 3}]), + <<"11">> = bformat("{three:b}", [{<<"three">>, 3}]), + <<"\"foo\"">> = bformat("{0!r}", {"foo"}), + <<"2008-5-4">> = bformat("{0.0}-{0.1}-{0.2}", {{2008,5,4}}), + <<"2008-05-04">> = bformat("{0.0:04}-{0.1:02}-{0.2:02}", {{2008,5,4}}), + <<"foo6bar-6">> = bformat("foo{1}{0}-{1}", {bar, 6}), + <<"-'atom test'-">> = bformat("-{arg!r}-", [{arg, 'atom test'}]), + <<"2008-05-04">> = bformat("{0.0:0{1.0}}-{0.1:0{1.1}}-{0.2:0{1.2}}", + {{2008,5,4}, {4, 2, 2}}), + ok. + +std_test() -> + M = mochifmt_std:new(), + <<"01">> = bformat("{0}{1}", [0, 1], M), + ok. + +records_test() -> + M = mochifmt_records:new([{conversion, record_info(fields, conversion)}]), + R = #conversion{length=long, precision=hard, sign=peace}, + long = M:get_value("length", R), + hard = M:get_value("precision", R), + peace = M:get_value("sign", R), + <<"long hard">> = bformat("{length} {precision}", R, M), + <<"long hard">> = bformat("{0.length} {0.precision}", [R], M), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochifmt_records.erl b/deps/mochiweb/src/mochifmt_records.erl new file mode 100644 index 0000000..3dccaa4 --- /dev/null +++ b/deps/mochiweb/src/mochifmt_records.erl @@ -0,0 +1,60 @@ +%% @author Bob Ippolito +%% @copyright 2008 Mochi Media, Inc. +%% +%% 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. + +%% @doc Formatter that understands records. +%% +%% Usage: +%% +%% 1> M = mochifmt_records:new([{rec, record_info(fields, rec)}]), +%% M:format("{0.bar}", [#rec{bar=foo}]). +%% foo + +-module(mochifmt_records). +-author('bob@mochimedia.com'). +-export([new/1, get_value/3]). + +new([{_Rec, RecFields}]=Recs) when is_list(RecFields) -> + {?MODULE, Recs}. + +get_value(Key, Rec, {?MODULE, Recs}) + when is_tuple(Rec) and is_atom(element(1, Rec)) -> + try begin + Atom = list_to_existing_atom(Key), + {_, Fields} = proplists:lookup(element(1, Rec), Recs), + element(get_rec_index(Atom, Fields, 2), Rec) + end + catch error:_ -> mochifmt:get_value(Key, Rec) + end; +get_value(Key, Args, {?MODULE, _Recs}) -> + mochifmt:get_value(Key, Args). + +get_rec_index(Atom, [Atom | _], Index) -> + Index; +get_rec_index(Atom, [_ | Rest], Index) -> + get_rec_index(Atom, Rest, 1 + Index). + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochifmt_std.erl b/deps/mochiweb/src/mochifmt_std.erl new file mode 100644 index 0000000..6067451 --- /dev/null +++ b/deps/mochiweb/src/mochifmt_std.erl @@ -0,0 +1,51 @@ +%% @author Bob Ippolito +%% @copyright 2008 Mochi Media, Inc. +%% +%% 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. + +%% @doc Template module for a mochifmt formatter. + +-module(mochifmt_std). +-author('bob@mochimedia.com'). +-export([new/0, format/3, get_value/3, format_field/3, get_field/3, convert_field/3]). + +new() -> + {?MODULE}. + +format(Format, Args, {?MODULE}=THIS) -> + mochifmt:format(Format, Args, THIS). + +get_field(Key, Args, {?MODULE}=THIS) -> + mochifmt:get_field(Key, Args, THIS). + +convert_field(Key, Args, {?MODULE}) -> + mochifmt:convert_field(Key, Args). + +get_value(Key, Args, {?MODULE}) -> + mochifmt:get_value(Key, Args). + +format_field(Arg, Format, {?MODULE}=THIS) -> + mochifmt:format_field(Arg, Format, THIS). + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochiglobal.erl b/deps/mochiweb/src/mochiglobal.erl new file mode 100644 index 0000000..8df007f --- /dev/null +++ b/deps/mochiweb/src/mochiglobal.erl @@ -0,0 +1,127 @@ +%% @author Bob Ippolito +%% @copyright 2010 Mochi Media, Inc. +%% +%% 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. + + +%% @doc Abuse module constant pools as a "read-only shared heap" (since erts 5.6) +%% [1]. +-module(mochiglobal). +-author("Bob Ippolito "). +-export([get/1, get/2, put/2, delete/1]). + +-spec get(atom()) -> any() | undefined. +%% @equiv get(K, undefined) +get(K) -> + get(K, undefined). + +-spec get(atom(), T) -> any() | T. +%% @doc Get the term for K or return Default. +get(K, Default) -> + get(K, Default, key_to_module(K)). + +get(_K, Default, Mod) -> + try Mod:term() + catch error:undef -> + Default + end. + +-spec put(atom(), any()) -> ok. +%% @doc Store term V at K, replaces an existing term if present. +put(K, V) -> + put(K, V, key_to_module(K)). + +put(_K, V, Mod) -> + Bin = compile(Mod, V), + code:purge(Mod), + {module, Mod} = code:load_binary(Mod, atom_to_list(Mod) ++ ".erl", Bin), + ok. + +-spec delete(atom()) -> boolean(). +%% @doc Delete term stored at K, no-op if non-existent. +delete(K) -> + delete(K, key_to_module(K)). + +delete(_K, Mod) -> + code:purge(Mod), + code:delete(Mod). + +-spec key_to_module(atom()) -> atom(). +key_to_module(K) -> + list_to_atom("mochiglobal:" ++ atom_to_list(K)). + +-spec compile(atom(), any()) -> binary(). +compile(Module, T) -> + {ok, Module, Bin} = compile:forms(forms(Module, T), + [verbose, report_errors]), + Bin. + +-spec forms(atom(), any()) -> [erl_syntax:syntaxTree()]. +forms(Module, T) -> + [erl_syntax:revert(X) || X <- term_to_abstract(Module, term, T)]. + +-spec term_to_abstract(atom(), atom(), any()) -> [erl_syntax:syntaxTree()]. +term_to_abstract(Module, Getter, T) -> + [%% -module(Module). + erl_syntax:attribute( + erl_syntax:atom(module), + [erl_syntax:atom(Module)]), + %% -export([Getter/0]). + erl_syntax:attribute( + erl_syntax:atom(export), + [erl_syntax:list( + [erl_syntax:arity_qualifier( + erl_syntax:atom(Getter), + erl_syntax:integer(0))])]), + %% Getter() -> T. + erl_syntax:function( + erl_syntax:atom(Getter), + [erl_syntax:clause([], none, [erl_syntax:abstract(T)])])]. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +get_put_delete_test() -> + K = '$$test$$mochiglobal', + delete(K), + ?assertEqual( + bar, + get(K, bar)), + try + ?MODULE:put(K, baz), + ?assertEqual( + baz, + get(K, bar)), + ?MODULE:put(K, wibble), + ?assertEqual( + wibble, + ?MODULE:get(K)) + after + delete(K) + end, + ?assertEqual( + bar, + get(K, bar)), + ?assertEqual( + undefined, + ?MODULE:get(K)), + ok. +-endif. diff --git a/deps/mochiweb/src/mochihex.erl b/deps/mochiweb/src/mochihex.erl new file mode 100644 index 0000000..91b2789 --- /dev/null +++ b/deps/mochiweb/src/mochihex.erl @@ -0,0 +1,106 @@ +%% @author Bob Ippolito +%% @copyright 2006 Mochi Media, Inc. +%% +%% 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. + +%% @doc Utilities for working with hexadecimal strings. + +-module(mochihex). +-author('bob@mochimedia.com'). + +-export([to_hex/1, to_bin/1, to_int/1, dehex/1, hexdigit/1]). + +%% @spec to_hex(integer | iolist()) -> string() +%% @doc Convert an iolist to a hexadecimal string. +to_hex(0) -> + "0"; +to_hex(I) when is_integer(I), I > 0 -> + to_hex_int(I, []); +to_hex(B) -> + to_hex(iolist_to_binary(B), []). + +%% @spec to_bin(string()) -> binary() +%% @doc Convert a hexadecimal string to a binary. +to_bin(L) -> + to_bin(L, []). + +%% @spec to_int(string()) -> integer() +%% @doc Convert a hexadecimal string to an integer. +to_int(L) -> + erlang:list_to_integer(L, 16). + +%% @spec dehex(char()) -> integer() +%% @doc Convert a hex digit to its integer value. +dehex(C) when C >= $0, C =< $9 -> + C - $0; +dehex(C) when C >= $a, C =< $f -> + C - $a + 10; +dehex(C) when C >= $A, C =< $F -> + C - $A + 10. + +%% @spec hexdigit(integer()) -> char() +%% @doc Convert an integer less than 16 to a hex digit. +hexdigit(C) when C >= 0, C =< 9 -> + C + $0; +hexdigit(C) when C =< 15 -> + C + $a - 10. + +%% Internal API + +to_hex(<<>>, Acc) -> + lists:reverse(Acc); +to_hex(<>, Acc) -> + to_hex(Rest, [hexdigit(C2), hexdigit(C1) | Acc]). + +to_hex_int(0, Acc) -> + Acc; +to_hex_int(I, Acc) -> + to_hex_int(I bsr 4, [hexdigit(I band 15) | Acc]). + +to_bin([], Acc) -> + iolist_to_binary(lists:reverse(Acc)); +to_bin([C1, C2 | Rest], Acc) -> + to_bin(Rest, [(dehex(C1) bsl 4) bor dehex(C2) | Acc]). + + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +to_hex_test() -> + "ff000ff1" = to_hex([255, 0, 15, 241]), + "ff000ff1" = to_hex(16#ff000ff1), + "0" = to_hex(16#0), + ok. + +to_bin_test() -> + <<255, 0, 15, 241>> = to_bin("ff000ff1"), + <<255, 0, 10, 161>> = to_bin("Ff000aA1"), + ok. + +to_int_test() -> + 16#ff000ff1 = to_int("ff000ff1"), + 16#ff000aa1 = to_int("FF000Aa1"), + 16#0 = to_int("0"), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochijson.erl b/deps/mochiweb/src/mochijson.erl new file mode 100644 index 0000000..fb9b1dc --- /dev/null +++ b/deps/mochiweb/src/mochijson.erl @@ -0,0 +1,547 @@ +%% @author Bob Ippolito +%% @copyright 2006 Mochi Media, Inc. +%% +%% 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. + +%% @doc Yet another JSON (RFC 4627) library for Erlang. +-module(mochijson). +-author('bob@mochimedia.com'). +-export([encoder/1, encode/1]). +-export([decoder/1, decode/1]). +-export([binary_encoder/1, binary_encode/1]). +-export([binary_decoder/1, binary_decode/1]). + +% This is a macro to placate syntax highlighters.. +-define(Q, $\"). +-define(ADV_COL(S, N), S#decoder{column=N+S#decoder.column}). +-define(INC_COL(S), S#decoder{column=1+S#decoder.column}). +-define(INC_LINE(S), S#decoder{column=1, line=1+S#decoder.line}). + +%% @type json_string() = atom | string() | binary() +%% @type json_number() = integer() | float() +%% @type json_array() = {array, [json_term()]} +%% @type json_object() = {struct, [{json_string(), json_term()}]} +%% @type json_term() = json_string() | json_number() | json_array() | +%% json_object() +%% @type encoding() = utf8 | unicode +%% @type encoder_option() = {input_encoding, encoding()} | +%% {handler, function()} +%% @type decoder_option() = {input_encoding, encoding()} | +%% {object_hook, function()} +%% @type bjson_string() = binary() +%% @type bjson_number() = integer() | float() +%% @type bjson_array() = [bjson_term()] +%% @type bjson_object() = {struct, [{bjson_string(), bjson_term()}]} +%% @type bjson_term() = bjson_string() | bjson_number() | bjson_array() | +%% bjson_object() +%% @type binary_encoder_option() = {handler, function()} +%% @type binary_decoder_option() = {object_hook, function()} + +-record(encoder, {input_encoding=unicode, + handler=null}). + +-record(decoder, {input_encoding=utf8, + object_hook=null, + line=1, + column=1, + state=null}). + +%% @spec encoder([encoder_option()]) -> function() +%% @doc Create an encoder/1 with the given options. +encoder(Options) -> + State = parse_encoder_options(Options, #encoder{}), + fun (O) -> json_encode(O, State) end. + +%% @spec encode(json_term()) -> iolist() +%% @doc Encode the given as JSON to an iolist. +encode(Any) -> + json_encode(Any, #encoder{}). + +%% @spec decoder([decoder_option()]) -> function() +%% @doc Create a decoder/1 with the given options. +decoder(Options) -> + State = parse_decoder_options(Options, #decoder{}), + fun (O) -> json_decode(O, State) end. + +%% @spec decode(iolist()) -> json_term() +%% @doc Decode the given iolist to Erlang terms. +decode(S) -> + json_decode(S, #decoder{}). + +%% @spec binary_decoder([binary_decoder_option()]) -> function() +%% @doc Create a binary_decoder/1 with the given options. +binary_decoder(Options) -> + mochijson2:decoder(Options). + +%% @spec binary_encoder([binary_encoder_option()]) -> function() +%% @doc Create a binary_encoder/1 with the given options. +binary_encoder(Options) -> + mochijson2:encoder(Options). + +%% @spec binary_encode(bjson_term()) -> iolist() +%% @doc Encode the given as JSON to an iolist, using lists for arrays and +%% binaries for strings. +binary_encode(Any) -> + mochijson2:encode(Any). + +%% @spec binary_decode(iolist()) -> bjson_term() +%% @doc Decode the given iolist to Erlang terms, using lists for arrays and +%% binaries for strings. +binary_decode(S) -> + mochijson2:decode(S). + +%% Internal API + +parse_encoder_options([], State) -> + State; +parse_encoder_options([{input_encoding, Encoding} | Rest], State) -> + parse_encoder_options(Rest, State#encoder{input_encoding=Encoding}); +parse_encoder_options([{handler, Handler} | Rest], State) -> + parse_encoder_options(Rest, State#encoder{handler=Handler}). + +parse_decoder_options([], State) -> + State; +parse_decoder_options([{input_encoding, Encoding} | Rest], State) -> + parse_decoder_options(Rest, State#decoder{input_encoding=Encoding}); +parse_decoder_options([{object_hook, Hook} | Rest], State) -> + parse_decoder_options(Rest, State#decoder{object_hook=Hook}). + +json_encode(true, _State) -> + "true"; +json_encode(false, _State) -> + "false"; +json_encode(null, _State) -> + "null"; +json_encode(I, _State) when is_integer(I) -> + integer_to_list(I); +json_encode(F, _State) when is_float(F) -> + mochinum:digits(F); +json_encode(L, State) when is_list(L); is_binary(L); is_atom(L) -> + json_encode_string(L, State); +json_encode({array, Props}, State) when is_list(Props) -> + json_encode_array(Props, State); +json_encode({struct, Props}, State) when is_list(Props) -> + json_encode_proplist(Props, State); +json_encode(Bad, #encoder{handler=null}) -> + exit({json_encode, {bad_term, Bad}}); +json_encode(Bad, State=#encoder{handler=Handler}) -> + json_encode(Handler(Bad), State). + +json_encode_array([], _State) -> + "[]"; +json_encode_array(L, State) -> + F = fun (O, Acc) -> + [$,, json_encode(O, State) | Acc] + end, + [$, | Acc1] = lists:foldl(F, "[", L), + lists:reverse([$\] | Acc1]). + +json_encode_proplist([], _State) -> + "{}"; +json_encode_proplist(Props, State) -> + F = fun ({K, V}, Acc) -> + KS = case K of + K when is_atom(K) -> + json_encode_string_utf8(atom_to_list(K)); + K when is_integer(K) -> + json_encode_string(integer_to_list(K), State); + K when is_list(K); is_binary(K) -> + json_encode_string(K, State) + end, + VS = json_encode(V, State), + [$,, VS, $:, KS | Acc] + end, + [$, | Acc1] = lists:foldl(F, "{", Props), + lists:reverse([$\} | Acc1]). + +json_encode_string(A, _State) when is_atom(A) -> + json_encode_string_unicode(xmerl_ucs:from_utf8(atom_to_list(A))); +json_encode_string(B, _State) when is_binary(B) -> + json_encode_string_unicode(xmerl_ucs:from_utf8(B)); +json_encode_string(S, #encoder{input_encoding=utf8}) -> + json_encode_string_utf8(S); +json_encode_string(S, #encoder{input_encoding=unicode}) -> + json_encode_string_unicode(S). + +json_encode_string_utf8(S) -> + [?Q | json_encode_string_utf8_1(S)]. + +json_encode_string_utf8_1([C | Cs]) when C >= 0, C =< 16#7f -> + NewC = case C of + $\\ -> "\\\\"; + ?Q -> "\\\""; + _ when C >= $\s, C < 16#7f -> C; + $\t -> "\\t"; + $\n -> "\\n"; + $\r -> "\\r"; + $\f -> "\\f"; + $\b -> "\\b"; + _ when C >= 0, C =< 16#7f -> unihex(C); + _ -> exit({json_encode, {bad_char, C}}) + end, + [NewC | json_encode_string_utf8_1(Cs)]; +json_encode_string_utf8_1(All=[C | _]) when C >= 16#80, C =< 16#10FFFF -> + [?Q | Rest] = json_encode_string_unicode(xmerl_ucs:from_utf8(All)), + Rest; +json_encode_string_utf8_1([]) -> + "\"". + +json_encode_string_unicode(S) -> + [?Q | json_encode_string_unicode_1(S)]. + +json_encode_string_unicode_1([C | Cs]) -> + NewC = case C of + $\\ -> "\\\\"; + ?Q -> "\\\""; + _ when C >= $\s, C < 16#7f -> C; + $\t -> "\\t"; + $\n -> "\\n"; + $\r -> "\\r"; + $\f -> "\\f"; + $\b -> "\\b"; + _ when C >= 0, C =< 16#10FFFF -> unihex(C); + _ -> exit({json_encode, {bad_char, C}}) + end, + [NewC | json_encode_string_unicode_1(Cs)]; +json_encode_string_unicode_1([]) -> + "\"". + +dehex(C) when C >= $0, C =< $9 -> + C - $0; +dehex(C) when C >= $a, C =< $f -> + C - $a + 10; +dehex(C) when C >= $A, C =< $F -> + C - $A + 10. + +hexdigit(C) when C >= 0, C =< 9 -> + C + $0; +hexdigit(C) when C =< 15 -> + C + $a - 10. + +unihex(C) when C < 16#10000 -> + <> = <>, + Digits = [hexdigit(D) || D <- [D3, D2, D1, D0]], + [$\\, $u | Digits]; +unihex(C) when C =< 16#10FFFF -> + N = C - 16#10000, + S1 = 16#d800 bor ((N bsr 10) band 16#3ff), + S2 = 16#dc00 bor (N band 16#3ff), + [unihex(S1), unihex(S2)]. + +json_decode(B, S) when is_binary(B) -> + json_decode(binary_to_list(B), S); +json_decode(L, S) -> + {Res, L1, S1} = decode1(L, S), + {eof, [], _} = tokenize(L1, S1#decoder{state=trim}), + Res. + +decode1(L, S=#decoder{state=null}) -> + case tokenize(L, S#decoder{state=any}) of + {{const, C}, L1, S1} -> + {C, L1, S1}; + {start_array, L1, S1} -> + decode_array(L1, S1#decoder{state=any}, []); + {start_object, L1, S1} -> + decode_object(L1, S1#decoder{state=key}, []) + end. + +make_object(V, #decoder{object_hook=null}) -> + V; +make_object(V, #decoder{object_hook=Hook}) -> + Hook(V). + +decode_object(L, S=#decoder{state=key}, Acc) -> + case tokenize(L, S) of + {end_object, Rest, S1} -> + V = make_object({struct, lists:reverse(Acc)}, S1), + {V, Rest, S1#decoder{state=null}}; + {{const, K}, Rest, S1} when is_list(K) -> + {colon, L2, S2} = tokenize(Rest, S1), + {V, L3, S3} = decode1(L2, S2#decoder{state=null}), + decode_object(L3, S3#decoder{state=comma}, [{K, V} | Acc]) + end; +decode_object(L, S=#decoder{state=comma}, Acc) -> + case tokenize(L, S) of + {end_object, Rest, S1} -> + V = make_object({struct, lists:reverse(Acc)}, S1), + {V, Rest, S1#decoder{state=null}}; + {comma, Rest, S1} -> + decode_object(Rest, S1#decoder{state=key}, Acc) + end. + +decode_array(L, S=#decoder{state=any}, Acc) -> + case tokenize(L, S) of + {end_array, Rest, S1} -> + {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}}; + {start_array, Rest, S1} -> + {Array, Rest1, S2} = decode_array(Rest, S1#decoder{state=any}, []), + decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]); + {start_object, Rest, S1} -> + {Array, Rest1, S2} = decode_object(Rest, S1#decoder{state=key}, []), + decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]); + {{const, Const}, Rest, S1} -> + decode_array(Rest, S1#decoder{state=comma}, [Const | Acc]) + end; +decode_array(L, S=#decoder{state=comma}, Acc) -> + case tokenize(L, S) of + {end_array, Rest, S1} -> + {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}}; + {comma, Rest, S1} -> + decode_array(Rest, S1#decoder{state=any}, Acc) + end. + +tokenize_string(IoList=[C | _], S=#decoder{input_encoding=utf8}, Acc) + when is_list(C); is_binary(C); C >= 16#7f -> + List = xmerl_ucs:from_utf8(iolist_to_binary(IoList)), + tokenize_string(List, S#decoder{input_encoding=unicode}, Acc); +tokenize_string("\"" ++ Rest, S, Acc) -> + {lists:reverse(Acc), Rest, ?INC_COL(S)}; +tokenize_string("\\\"" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\" | Acc]); +tokenize_string("\\\\" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\\ | Acc]); +tokenize_string("\\/" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$/ | Acc]); +tokenize_string("\\b" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\b | Acc]); +tokenize_string("\\f" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\f | Acc]); +tokenize_string("\\n" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\n | Acc]); +tokenize_string("\\r" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\r | Acc]); +tokenize_string("\\t" ++ Rest, S, Acc) -> + tokenize_string(Rest, ?ADV_COL(S, 2), [$\t | Acc]); +tokenize_string([$\\, $u, C3, C2, C1, C0 | Rest], S, Acc) -> + % coalesce UTF-16 surrogate pair? + C = dehex(C0) bor + (dehex(C1) bsl 4) bor + (dehex(C2) bsl 8) bor + (dehex(C3) bsl 12), + tokenize_string(Rest, ?ADV_COL(S, 6), [C | Acc]); +tokenize_string([C | Rest], S, Acc) when C >= $\s; C < 16#10FFFF -> + tokenize_string(Rest, ?ADV_COL(S, 1), [C | Acc]). + +tokenize_number(IoList=[C | _], Mode, S=#decoder{input_encoding=utf8}, Acc) + when is_list(C); is_binary(C); C >= 16#7f -> + List = xmerl_ucs:from_utf8(iolist_to_binary(IoList)), + tokenize_number(List, Mode, S#decoder{input_encoding=unicode}, Acc); +tokenize_number([$- | Rest], sign, S, []) -> + tokenize_number(Rest, int, ?INC_COL(S), [$-]); +tokenize_number(Rest, sign, S, []) -> + tokenize_number(Rest, int, S, []); +tokenize_number([$0 | Rest], int, S, Acc) -> + tokenize_number(Rest, frac, ?INC_COL(S), [$0 | Acc]); +tokenize_number([C | Rest], int, S, Acc) when C >= $1, C =< $9 -> + tokenize_number(Rest, int1, ?INC_COL(S), [C | Acc]); +tokenize_number([C | Rest], int1, S, Acc) when C >= $0, C =< $9 -> + tokenize_number(Rest, int1, ?INC_COL(S), [C | Acc]); +tokenize_number(Rest, int1, S, Acc) -> + tokenize_number(Rest, frac, S, Acc); +tokenize_number([$., C | Rest], frac, S, Acc) when C >= $0, C =< $9 -> + tokenize_number(Rest, frac1, ?ADV_COL(S, 2), [C, $. | Acc]); +tokenize_number([E | Rest], frac, S, Acc) when E == $e; E == $E -> + tokenize_number(Rest, esign, ?INC_COL(S), [$e, $0, $. | Acc]); +tokenize_number(Rest, frac, S, Acc) -> + {{int, lists:reverse(Acc)}, Rest, S}; +tokenize_number([C | Rest], frac1, S, Acc) when C >= $0, C =< $9 -> + tokenize_number(Rest, frac1, ?INC_COL(S), [C | Acc]); +tokenize_number([E | Rest], frac1, S, Acc) when E == $e; E == $E -> + tokenize_number(Rest, esign, ?INC_COL(S), [$e | Acc]); +tokenize_number(Rest, frac1, S, Acc) -> + {{float, lists:reverse(Acc)}, Rest, S}; +tokenize_number([C | Rest], esign, S, Acc) when C == $-; C == $+ -> + tokenize_number(Rest, eint, ?INC_COL(S), [C | Acc]); +tokenize_number(Rest, esign, S, Acc) -> + tokenize_number(Rest, eint, S, Acc); +tokenize_number([C | Rest], eint, S, Acc) when C >= $0, C =< $9 -> + tokenize_number(Rest, eint1, ?INC_COL(S), [C | Acc]); +tokenize_number([C | Rest], eint1, S, Acc) when C >= $0, C =< $9 -> + tokenize_number(Rest, eint1, ?INC_COL(S), [C | Acc]); +tokenize_number(Rest, eint1, S, Acc) -> + {{float, lists:reverse(Acc)}, Rest, S}. + +tokenize([], S=#decoder{state=trim}) -> + {eof, [], S}; +tokenize([L | Rest], S) when is_list(L) -> + tokenize(L ++ Rest, S); +tokenize([B | Rest], S) when is_binary(B) -> + tokenize(xmerl_ucs:from_utf8(B) ++ Rest, S); +tokenize("\r\n" ++ Rest, S) -> + tokenize(Rest, ?INC_LINE(S)); +tokenize("\n" ++ Rest, S) -> + tokenize(Rest, ?INC_LINE(S)); +tokenize([C | Rest], S) when C == $\s; C == $\t -> + tokenize(Rest, ?INC_COL(S)); +tokenize("{" ++ Rest, S) -> + {start_object, Rest, ?INC_COL(S)}; +tokenize("}" ++ Rest, S) -> + {end_object, Rest, ?INC_COL(S)}; +tokenize("[" ++ Rest, S) -> + {start_array, Rest, ?INC_COL(S)}; +tokenize("]" ++ Rest, S) -> + {end_array, Rest, ?INC_COL(S)}; +tokenize("," ++ Rest, S) -> + {comma, Rest, ?INC_COL(S)}; +tokenize(":" ++ Rest, S) -> + {colon, Rest, ?INC_COL(S)}; +tokenize("null" ++ Rest, S) -> + {{const, null}, Rest, ?ADV_COL(S, 4)}; +tokenize("true" ++ Rest, S) -> + {{const, true}, Rest, ?ADV_COL(S, 4)}; +tokenize("false" ++ Rest, S) -> + {{const, false}, Rest, ?ADV_COL(S, 5)}; +tokenize("\"" ++ Rest, S) -> + {String, Rest1, S1} = tokenize_string(Rest, ?INC_COL(S), []), + {{const, String}, Rest1, S1}; +tokenize(L=[C | _], S) when C >= $0, C =< $9; C == $- -> + case tokenize_number(L, sign, S, []) of + {{int, Int}, Rest, S1} -> + {{const, list_to_integer(Int)}, Rest, S1}; + {{float, Float}, Rest, S1} -> + {{const, list_to_float(Float)}, Rest, S1} + end. + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +%% testing constructs borrowed from the Yaws JSON implementation. + +%% Create an object from a list of Key/Value pairs. + +obj_new() -> + {struct, []}. + +is_obj({struct, Props}) -> + F = fun ({K, _}) when is_list(K) -> + true; + (_) -> + false + end, + lists:all(F, Props). + +obj_from_list(Props) -> + Obj = {struct, Props}, + case is_obj(Obj) of + true -> Obj; + false -> exit(json_bad_object) + end. + +%% Test for equivalence of Erlang terms. +%% Due to arbitrary order of construction, equivalent objects might +%% compare unequal as erlang terms, so we need to carefully recurse +%% through aggregates (tuples and objects). + +equiv({struct, Props1}, {struct, Props2}) -> + equiv_object(Props1, Props2); +equiv({array, L1}, {array, L2}) -> + equiv_list(L1, L2); +equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 == N2; +equiv(S1, S2) when is_list(S1), is_list(S2) -> S1 == S2; +equiv(true, true) -> true; +equiv(false, false) -> true; +equiv(null, null) -> true. + +%% Object representation and traversal order is unknown. +%% Use the sledgehammer and sort property lists. + +equiv_object(Props1, Props2) -> + L1 = lists:keysort(1, Props1), + L2 = lists:keysort(1, Props2), + Pairs = lists:zip(L1, L2), + true = lists:all(fun({{K1, V1}, {K2, V2}}) -> + equiv(K1, K2) and equiv(V1, V2) + end, Pairs). + +%% Recursively compare tuple elements for equivalence. + +equiv_list([], []) -> + true; +equiv_list([V1 | L1], [V2 | L2]) -> + equiv(V1, V2) andalso equiv_list(L1, L2). + +e2j_vec_test() -> + test_one(e2j_test_vec(utf8), 1). + +issue33_test() -> + %% http://code.google.com/p/mochiweb/issues/detail?id=33 + Js = {struct, [{"key", [194, 163]}]}, + Encoder = encoder([{input_encoding, utf8}]), + "{\"key\":\"\\u00a3\"}" = lists:flatten(Encoder(Js)). + +test_one([], _N) -> + %% io:format("~p tests passed~n", [N-1]), + ok; +test_one([{E, J} | Rest], N) -> + %% io:format("[~p] ~p ~p~n", [N, E, J]), + true = equiv(E, decode(J)), + true = equiv(E, decode(encode(E))), + test_one(Rest, 1+N). + +e2j_test_vec(utf8) -> + [ + {1, "1"}, + {3.1416, "3.14160"}, % text representation may truncate, trail zeroes + {-1, "-1"}, + {-3.1416, "-3.14160"}, + {12.0e10, "1.20000e+11"}, + {1.234E+10, "1.23400e+10"}, + {-1.234E-10, "-1.23400e-10"}, + {10.0, "1.0e+01"}, + {123.456, "1.23456E+2"}, + {10.0, "1e1"}, + {"foo", "\"foo\""}, + {"foo" ++ [5] ++ "bar", "\"foo\\u0005bar\""}, + {"", "\"\""}, + {"\"", "\"\\\"\""}, + {"\n\n\n", "\"\\n\\n\\n\""}, + {"\\", "\"\\\\\""}, + {"\" \b\f\r\n\t\"", "\"\\\" \\b\\f\\r\\n\\t\\\"\""}, + {obj_new(), "{}"}, + {obj_from_list([{"foo", "bar"}]), "{\"foo\":\"bar\"}"}, + {obj_from_list([{"foo", "bar"}, {"baz", 123}]), + "{\"foo\":\"bar\",\"baz\":123}"}, + {{array, []}, "[]"}, + {{array, [{array, []}]}, "[[]]"}, + {{array, [1, "foo"]}, "[1,\"foo\"]"}, + + % json array in a json object + {obj_from_list([{"foo", {array, [123]}}]), + "{\"foo\":[123]}"}, + + % json object in a json object + {obj_from_list([{"foo", obj_from_list([{"bar", true}])}]), + "{\"foo\":{\"bar\":true}}"}, + + % fold evaluation order + {obj_from_list([{"foo", {array, []}}, + {"bar", obj_from_list([{"baz", true}])}, + {"alice", "bob"}]), + "{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}"}, + + % json object in a json array + {{array, [-123, "foo", obj_from_list([{"bar", {array, []}}]), null]}, + "[-123,\"foo\",{\"bar\":[]},null]"} + ]. + +-endif. diff --git a/deps/mochiweb/src/mochijson2.erl b/deps/mochiweb/src/mochijson2.erl new file mode 100644 index 0000000..255398d --- /dev/null +++ b/deps/mochiweb/src/mochijson2.erl @@ -0,0 +1,942 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Yet another JSON (RFC 4627) library for Erlang. mochijson2 works +%% with binaries as strings, arrays as lists (without an {array, _}) +%% wrapper and it only knows how to decode UTF-8 (and ASCII). +%% +%% JSON terms are decoded as follows (javascript -> erlang): +%%
    +%%
  • {"key": "value"} -> +%% {struct, [{<<"key">>, <<"value">>}]}
  • +%%
  • ["array", 123, 12.34, true, false, null] -> +%% [<<"array">>, 123, 12.34, true, false, null] +%%
  • +%%
+%%
    +%%
  • Strings in JSON decode to UTF-8 binaries in Erlang
  • +%%
  • Objects decode to {struct, PropList}
  • +%%
  • Numbers decode to integer or float
  • +%%
  • true, false, null decode to their respective terms.
  • +%%
+%% The encoder will accept the same format that the decoder will produce, +%% but will also allow additional cases for leniency: +%%
    +%%
  • atoms other than true, false, null will be considered UTF-8 +%% strings (even as a proplist key) +%%
  • +%%
  • {json, IoList} will insert IoList directly into the output +%% with no validation +%%
  • +%%
  • {array, Array} will be encoded as Array +%% (legacy mochijson style) +%%
  • +%%
  • A non-empty raw proplist will be encoded as an object as long +%% as the first pair does not have an atom key of json, struct, +%% or array +%%
  • +%%
+ +-module(mochijson2). +-author('bob@mochimedia.com'). +-export([encoder/1, encode/1]). +-export([decoder/1, decode/1, decode/2]). + +%% This is a macro to placate syntax highlighters.. +-define(Q, $\"). +-define(ADV_COL(S, N), S#decoder{offset=N+S#decoder.offset, + column=N+S#decoder.column}). +-define(INC_COL(S), S#decoder{offset=1+S#decoder.offset, + column=1+S#decoder.column}). +-define(INC_LINE(S), S#decoder{offset=1+S#decoder.offset, + column=1, + line=1+S#decoder.line}). +-define(INC_CHAR(S, C), + case C of + $\n -> + S#decoder{column=1, + line=1+S#decoder.line, + offset=1+S#decoder.offset}; + _ -> + S#decoder{column=1+S#decoder.column, + offset=1+S#decoder.offset} + end). +-define(IS_WHITESPACE(C), + (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)). + +%% @type json_string() = atom | binary() +%% @type json_number() = integer() | float() +%% @type json_array() = [json_term()] +%% @type json_object() = {struct, [{json_string(), json_term()}]} +%% @type json_eep18_object() = {[{json_string(), json_term()}]} +%% @type json_iolist() = {json, iolist()} +%% @type json_term() = json_string() | json_number() | json_array() | +%% json_object() | json_eep18_object() | json_iolist() + +-record(encoder, {handler=null, + utf8=false}). + +-record(decoder, {object_hook=null, + offset=0, + line=1, + column=1, + state=null}). + +%% @spec encoder([encoder_option()]) -> function() +%% @doc Create an encoder/1 with the given options. +%% @type encoder_option() = handler_option() | utf8_option() +%% @type utf8_option() = boolean(). Emit unicode as utf8 (default - false) +encoder(Options) -> + State = parse_encoder_options(Options, #encoder{}), + fun (O) -> json_encode(O, State) end. + +%% @spec encode(json_term()) -> iolist() +%% @doc Encode the given as JSON to an iolist. +encode(Any) -> + json_encode(Any, #encoder{}). + +%% @spec decoder([decoder_option()]) -> function() +%% @doc Create a decoder/1 with the given options. +decoder(Options) -> + State = parse_decoder_options(Options, #decoder{}), + fun (O) -> json_decode(O, State) end. + +%% @spec decode(iolist(), [{format, proplist | eep18 | struct}]) -> json_term() +%% @doc Decode the given iolist to Erlang terms using the given object format +%% for decoding, where proplist returns JSON objects as [{binary(), json_term()}] +%% proplists, eep18 returns JSON objects as {[binary(), json_term()]}, and struct +%% returns them as-is. +decode(S, Options) -> + json_decode(S, parse_decoder_options(Options, #decoder{})). + +%% @spec decode(iolist()) -> json_term() +%% @doc Decode the given iolist to Erlang terms. +decode(S) -> + json_decode(S, #decoder{}). + +%% Internal API + +parse_encoder_options([], State) -> + State; +parse_encoder_options([{handler, Handler} | Rest], State) -> + parse_encoder_options(Rest, State#encoder{handler=Handler}); +parse_encoder_options([{utf8, Switch} | Rest], State) -> + parse_encoder_options(Rest, State#encoder{utf8=Switch}). + +parse_decoder_options([], State) -> + State; +parse_decoder_options([{object_hook, Hook} | Rest], State) -> + parse_decoder_options(Rest, State#decoder{object_hook=Hook}); +parse_decoder_options([{format, Format} | Rest], State) + when Format =:= struct orelse Format =:= eep18 orelse Format =:= proplist -> + parse_decoder_options(Rest, State#decoder{object_hook=Format}). + +json_encode(true, _State) -> + <<"true">>; +json_encode(false, _State) -> + <<"false">>; +json_encode(null, _State) -> + <<"null">>; +json_encode(I, _State) when is_integer(I) -> + integer_to_list(I); +json_encode(F, _State) when is_float(F) -> + mochinum:digits(F); +json_encode(S, State) when is_binary(S); is_atom(S) -> + json_encode_string(S, State); +json_encode([{K, _}|_] = Props, State) when (K =/= struct andalso + K =/= array andalso + K =/= json) -> + json_encode_proplist(Props, State); +json_encode({struct, Props}, State) when is_list(Props) -> + json_encode_proplist(Props, State); +json_encode({Props}, State) when is_list(Props) -> + json_encode_proplist(Props, State); +json_encode({}, State) -> + json_encode_proplist([], State); +json_encode(Array, State) when is_list(Array) -> + json_encode_array(Array, State); +json_encode({array, Array}, State) when is_list(Array) -> + json_encode_array(Array, State); +json_encode({json, IoList}, _State) -> + IoList; +json_encode(Bad, #encoder{handler=null}) -> + exit({json_encode, {bad_term, Bad}}); +json_encode(Bad, State=#encoder{handler=Handler}) -> + json_encode(Handler(Bad), State). + +json_encode_array([], _State) -> + <<"[]">>; +json_encode_array(L, State) -> + F = fun (O, Acc) -> + [$,, json_encode(O, State) | Acc] + end, + [$, | Acc1] = lists:foldl(F, "[", L), + lists:reverse([$\] | Acc1]). + +json_encode_proplist([], _State) -> + <<"{}">>; +json_encode_proplist(Props, State) -> + F = fun ({K, V}, Acc) -> + KS = json_encode_string(K, State), + VS = json_encode(V, State), + [$,, VS, $:, KS | Acc] + end, + [$, | Acc1] = lists:foldl(F, "{", Props), + lists:reverse([$\} | Acc1]). + +json_encode_string(A, State) when is_atom(A) -> + json_encode_string(atom_to_binary(A, latin1), State); +json_encode_string(B, State) when is_binary(B) -> + case json_bin_is_safe(B) of + true -> + [?Q, B, ?Q]; + false -> + json_encode_string_unicode(unicode:characters_to_list(B), State, [?Q]) + end; +json_encode_string(I, _State) when is_integer(I) -> + [?Q, integer_to_list(I), ?Q]; +json_encode_string(L, State) when is_list(L) -> + case json_string_is_safe(L) of + true -> + [?Q, L, ?Q]; + false -> + json_encode_string_unicode(L, State, [?Q]) + end. + +json_string_is_safe([]) -> + true; +json_string_is_safe([C | Rest]) -> + case C of + ?Q -> + false; + $\\ -> + false; + $\b -> + false; + $\f -> + false; + $\n -> + false; + $\r -> + false; + $\t -> + false; + C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF -> + false; + C when C < 16#7f -> + json_string_is_safe(Rest); + _ -> + exit({json_encode, {bad_char, C}}) + end. + +json_bin_is_safe(<<>>) -> + true; +json_bin_is_safe(<>) -> + case C of + ?Q -> + false; + $\\ -> + false; + $\b -> + false; + $\f -> + false; + $\n -> + false; + $\r -> + false; + $\t -> + false; + C when C >= 0, C < $\s; C >= 16#7f -> + false; + C when C < 16#7f -> + json_bin_is_safe(Rest) + end. + +json_encode_string_unicode([], _State, Acc) -> + lists:reverse([$\" | Acc]); +json_encode_string_unicode([C | Cs], State, Acc) -> + Acc1 = case C of + ?Q -> + [?Q, $\\ | Acc]; + %% Escaping solidus is only useful when trying to protect + %% against "" injection attacks which are only + %% possible when JSON is inserted into a HTML document + %% in-line. mochijson2 does not protect you from this, so + %% if you do insert directly into HTML then you need to + %% uncomment the following case or escape the output of encode. + %% + %% $/ -> + %% [$/, $\\ | Acc]; + %% + $\\ -> + [$\\, $\\ | Acc]; + $\b -> + [$b, $\\ | Acc]; + $\f -> + [$f, $\\ | Acc]; + $\n -> + [$n, $\\ | Acc]; + $\r -> + [$r, $\\ | Acc]; + $\t -> + [$t, $\\ | Acc]; + C when C >= 0, C < $\s -> + [unihex(C) | Acc]; + C when C >= 16#7f, C =< 16#10FFFF, State#encoder.utf8 -> + [unicode:characters_to_binary([C]) | Acc]; + C when C >= 16#7f, C =< 16#10FFFF, not State#encoder.utf8 -> + [unihex(C) | Acc]; + C when C < 16#7f -> + [C | Acc]; + _ -> + %% json_string_is_safe guarantees that this branch is dead + exit({json_encode, {bad_char, C}}) + end, + json_encode_string_unicode(Cs, State, Acc1). + +hexdigit(C) when C >= 0, C =< 9 -> + C + $0; +hexdigit(C) when C =< 15 -> + C + $a - 10. + +unihex(C) when C < 16#10000 -> + <> = <>, + Digits = [hexdigit(D) || D <- [D3, D2, D1, D0]], + [$\\, $u | Digits]; +unihex(C) when C =< 16#10FFFF -> + N = C - 16#10000, + S1 = 16#d800 bor ((N bsr 10) band 16#3ff), + S2 = 16#dc00 bor (N band 16#3ff), + [unihex(S1), unihex(S2)]. + +json_decode(L, S) when is_list(L) -> + json_decode(iolist_to_binary(L), S); +json_decode(B, S) -> + {Res, S1} = decode1(B, S), + {eof, _} = tokenize(B, S1#decoder{state=trim}), + Res. + +decode1(B, S=#decoder{state=null}) -> + case tokenize(B, S#decoder{state=any}) of + {{const, C}, S1} -> + {C, S1}; + {start_array, S1} -> + decode_array(B, S1); + {start_object, S1} -> + decode_object(B, S1) + end. + +make_object(V, #decoder{object_hook=N}) when N =:= null orelse N =:= struct -> + V; +make_object({struct, P}, #decoder{object_hook=eep18}) -> + {P}; +make_object({struct, P}, #decoder{object_hook=proplist}) -> + P; +make_object(V, #decoder{object_hook=Hook}) -> + Hook(V). + +decode_object(B, S) -> + decode_object(B, S#decoder{state=key}, []). + +decode_object(B, S=#decoder{state=key}, Acc) -> + case tokenize(B, S) of + {end_object, S1} -> + V = make_object({struct, lists:reverse(Acc)}, S1), + {V, S1#decoder{state=null}}; + {{const, K}, S1} -> + {colon, S2} = tokenize(B, S1), + {V, S3} = decode1(B, S2#decoder{state=null}), + decode_object(B, S3#decoder{state=comma}, [{K, V} | Acc]) + end; +decode_object(B, S=#decoder{state=comma}, Acc) -> + case tokenize(B, S) of + {end_object, S1} -> + V = make_object({struct, lists:reverse(Acc)}, S1), + {V, S1#decoder{state=null}}; + {comma, S1} -> + decode_object(B, S1#decoder{state=key}, Acc) + end. + +decode_array(B, S) -> + decode_array(B, S#decoder{state=any}, []). + +decode_array(B, S=#decoder{state=any}, Acc) -> + case tokenize(B, S) of + {end_array, S1} -> + {lists:reverse(Acc), S1#decoder{state=null}}; + {start_array, S1} -> + {Array, S2} = decode_array(B, S1), + decode_array(B, S2#decoder{state=comma}, [Array | Acc]); + {start_object, S1} -> + {Array, S2} = decode_object(B, S1), + decode_array(B, S2#decoder{state=comma}, [Array | Acc]); + {{const, Const}, S1} -> + decode_array(B, S1#decoder{state=comma}, [Const | Acc]) + end; +decode_array(B, S=#decoder{state=comma}, Acc) -> + case tokenize(B, S) of + {end_array, S1} -> + {lists:reverse(Acc), S1#decoder{state=null}}; + {comma, S1} -> + decode_array(B, S1#decoder{state=any}, Acc) + end. + +tokenize_string(B, S=#decoder{offset=O}) -> + case tokenize_string_fast(B, O) of + {escape, O1} -> + Length = O1 - O, + S1 = ?ADV_COL(S, Length), + <<_:O/binary, Head:Length/binary, _/binary>> = B, + tokenize_string(B, S1, lists:reverse(binary_to_list(Head))); + O1 -> + Length = O1 - O, + <<_:O/binary, String:Length/binary, ?Q, _/binary>> = B, + {{const, String}, ?ADV_COL(S, Length + 1)} + end. + +tokenize_string_fast(B, O) -> + case B of + <<_:O/binary, ?Q, _/binary>> -> + O; + <<_:O/binary, $\\, _/binary>> -> + {escape, O}; + <<_:O/binary, C1, _/binary>> when C1 < 128 -> + tokenize_string_fast(B, 1 + O); + <<_:O/binary, C1, C2, _/binary>> when C1 >= 194, C1 =< 223, + C2 >= 128, C2 =< 191 -> + tokenize_string_fast(B, 2 + O); + <<_:O/binary, C1, C2, C3, _/binary>> when C1 >= 224, C1 =< 239, + C2 >= 128, C2 =< 191, + C3 >= 128, C3 =< 191 -> + tokenize_string_fast(B, 3 + O); + <<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >= 240, C1 =< 244, + C2 >= 128, C2 =< 191, + C3 >= 128, C3 =< 191, + C4 >= 128, C4 =< 191 -> + tokenize_string_fast(B, 4 + O); + _ -> + throw(invalid_utf8) + end. + +tokenize_string(B, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, ?Q, _/binary>> -> + {{const, iolist_to_binary(lists:reverse(Acc))}, ?INC_COL(S)}; + <<_:O/binary, "\\\"", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\" | Acc]); + <<_:O/binary, "\\\\", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\\ | Acc]); + <<_:O/binary, "\\/", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$/ | Acc]); + <<_:O/binary, "\\b", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\b | Acc]); + <<_:O/binary, "\\f", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\f | Acc]); + <<_:O/binary, "\\n", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\n | Acc]); + <<_:O/binary, "\\r", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\r | Acc]); + <<_:O/binary, "\\t", _/binary>> -> + tokenize_string(B, ?ADV_COL(S, 2), [$\t | Acc]); + <<_:O/binary, "\\u", C3, C2, C1, C0, Rest/binary>> -> + C = erlang:list_to_integer([C3, C2, C1, C0], 16), + if C > 16#D7FF, C < 16#DC00 -> + %% coalesce UTF-16 surrogate pair + <<"\\u", D3, D2, D1, D0, _/binary>> = Rest, + D = erlang:list_to_integer([D3,D2,D1,D0], 16), + Acc1 = [unicode:characters_to_binary( + <>, + utf16) + | Acc], + tokenize_string(B, ?ADV_COL(S, 12), Acc1); + true -> + Acc1 = [unicode:characters_to_binary([C]) | Acc], + tokenize_string(B, ?ADV_COL(S, 6), Acc1) + end; + <<_:O/binary, C1, _/binary>> when C1 < 128 -> + tokenize_string(B, ?INC_CHAR(S, C1), [C1 | Acc]); + <<_:O/binary, C1, C2, _/binary>> when C1 >= 194, C1 =< 223, + C2 >= 128, C2 =< 191 -> + tokenize_string(B, ?ADV_COL(S, 2), [C2, C1 | Acc]); + <<_:O/binary, C1, C2, C3, _/binary>> when C1 >= 224, C1 =< 239, + C2 >= 128, C2 =< 191, + C3 >= 128, C3 =< 191 -> + tokenize_string(B, ?ADV_COL(S, 3), [C3, C2, C1 | Acc]); + <<_:O/binary, C1, C2, C3, C4, _/binary>> when C1 >= 240, C1 =< 244, + C2 >= 128, C2 =< 191, + C3 >= 128, C3 =< 191, + C4 >= 128, C4 =< 191 -> + tokenize_string(B, ?ADV_COL(S, 4), [C4, C3, C2, C1 | Acc]); + _ -> + throw(invalid_utf8) + end. + +tokenize_number(B, S) -> + case tokenize_number(B, sign, S, []) of + {{int, Int}, S1} -> + {{const, list_to_integer(Int)}, S1}; + {{float, Float}, S1} -> + {{const, list_to_float(Float)}, S1} + end. + +tokenize_number(B, sign, S=#decoder{offset=O}, []) -> + case B of + <<_:O/binary, $-, _/binary>> -> + tokenize_number(B, int, ?INC_COL(S), [$-]); + _ -> + tokenize_number(B, int, S, []) + end; +tokenize_number(B, int, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, $0, _/binary>> -> + tokenize_number(B, frac, ?INC_COL(S), [$0 | Acc]); + <<_:O/binary, C, _/binary>> when C >= $1 andalso C =< $9 -> + tokenize_number(B, int1, ?INC_COL(S), [C | Acc]) + end; +tokenize_number(B, int1, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> + tokenize_number(B, int1, ?INC_COL(S), [C | Acc]); + _ -> + tokenize_number(B, frac, S, Acc) + end; +tokenize_number(B, frac, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, $., C, _/binary>> when C >= $0, C =< $9 -> + tokenize_number(B, frac1, ?ADV_COL(S, 2), [C, $. | Acc]); + <<_:O/binary, E, _/binary>> when E =:= $e orelse E =:= $E -> + tokenize_number(B, esign, ?INC_COL(S), [$e, $0, $. | Acc]); + _ -> + {{int, lists:reverse(Acc)}, S} + end; +tokenize_number(B, frac1, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> + tokenize_number(B, frac1, ?INC_COL(S), [C | Acc]); + <<_:O/binary, E, _/binary>> when E =:= $e orelse E =:= $E -> + tokenize_number(B, esign, ?INC_COL(S), [$e | Acc]); + _ -> + {{float, lists:reverse(Acc)}, S} + end; +tokenize_number(B, esign, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, C, _/binary>> when C =:= $- orelse C=:= $+ -> + tokenize_number(B, eint, ?INC_COL(S), [C | Acc]); + _ -> + tokenize_number(B, eint, S, Acc) + end; +tokenize_number(B, eint, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> + tokenize_number(B, eint1, ?INC_COL(S), [C | Acc]) + end; +tokenize_number(B, eint1, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary, C, _/binary>> when C >= $0 andalso C =< $9 -> + tokenize_number(B, eint1, ?INC_COL(S), [C | Acc]); + _ -> + {{float, lists:reverse(Acc)}, S} + end. + +tokenize(B, S=#decoder{offset=O}) -> + case B of + <<_:O/binary, C, _/binary>> when ?IS_WHITESPACE(C) -> + tokenize(B, ?INC_CHAR(S, C)); + <<_:O/binary, "{", _/binary>> -> + {start_object, ?INC_COL(S)}; + <<_:O/binary, "}", _/binary>> -> + {end_object, ?INC_COL(S)}; + <<_:O/binary, "[", _/binary>> -> + {start_array, ?INC_COL(S)}; + <<_:O/binary, "]", _/binary>> -> + {end_array, ?INC_COL(S)}; + <<_:O/binary, ",", _/binary>> -> + {comma, ?INC_COL(S)}; + <<_:O/binary, ":", _/binary>> -> + {colon, ?INC_COL(S)}; + <<_:O/binary, "null", _/binary>> -> + {{const, null}, ?ADV_COL(S, 4)}; + <<_:O/binary, "true", _/binary>> -> + {{const, true}, ?ADV_COL(S, 4)}; + <<_:O/binary, "false", _/binary>> -> + {{const, false}, ?ADV_COL(S, 5)}; + <<_:O/binary, "\"", _/binary>> -> + tokenize_string(B, ?INC_COL(S)); + <<_:O/binary, C, _/binary>> when (C >= $0 andalso C =< $9) + orelse C =:= $- -> + tokenize_number(B, S); + <<_:O/binary>> -> + trim = S#decoder.state, + {eof, S} + end. +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + + +%% testing constructs borrowed from the Yaws JSON implementation. + +%% Create an object from a list of Key/Value pairs. + +obj_new() -> + {struct, []}. + +is_obj({struct, Props}) -> + F = fun ({K, _}) when is_binary(K) -> true end, + lists:all(F, Props). + +obj_from_list(Props) -> + Obj = {struct, Props}, + ?assert(is_obj(Obj)), + Obj. + +%% Test for equivalence of Erlang terms. +%% Due to arbitrary order of construction, equivalent objects might +%% compare unequal as erlang terms, so we need to carefully recurse +%% through aggregates (tuples and objects). + +equiv({struct, Props1}, {struct, Props2}) -> + equiv_object(Props1, Props2); +equiv(L1, L2) when is_list(L1), is_list(L2) -> + equiv_list(L1, L2); +equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 == N2; +equiv(B1, B2) when is_binary(B1), is_binary(B2) -> B1 == B2; +equiv(A, A) when A =:= true orelse A =:= false orelse A =:= null -> true. + +%% Object representation and traversal order is unknown. +%% Use the sledgehammer and sort property lists. + +equiv_object(Props1, Props2) -> + L1 = lists:keysort(1, Props1), + L2 = lists:keysort(1, Props2), + Pairs = lists:zip(L1, L2), + true = lists:all(fun({{K1, V1}, {K2, V2}}) -> + equiv(K1, K2) and equiv(V1, V2) + end, Pairs). + +%% Recursively compare tuple elements for equivalence. + +equiv_list([], []) -> + true; +equiv_list([V1 | L1], [V2 | L2]) -> + equiv(V1, V2) andalso equiv_list(L1, L2). + +decode_test() -> + [1199344435545.0, 1] = decode(<<"[1199344435545.0,1]">>), + <<16#F0,16#9D,16#9C,16#95>> = decode([34,"\\ud835","\\udf15",34]). + +e2j_vec_test() -> + test_one(e2j_test_vec(utf8), 1). + +test_one([], _N) -> + %% io:format("~p tests passed~n", [N-1]), + ok; +test_one([{E, J} | Rest], N) -> + %% io:format("[~p] ~p ~p~n", [N, E, J]), + true = equiv(E, decode(J)), + true = equiv(E, decode(encode(E))), + test_one(Rest, 1+N). + +e2j_test_vec(utf8) -> + [ + {1, "1"}, + {3.1416, "3.14160"}, %% text representation may truncate, trail zeroes + {-1, "-1"}, + {-3.1416, "-3.14160"}, + {12.0e10, "1.20000e+11"}, + {1.234E+10, "1.23400e+10"}, + {-1.234E-10, "-1.23400e-10"}, + {10.0, "1.0e+01"}, + {123.456, "1.23456E+2"}, + {10.0, "1e1"}, + {<<"foo">>, "\"foo\""}, + {<<"foo", 5, "bar">>, "\"foo\\u0005bar\""}, + {<<"">>, "\"\""}, + {<<"\n\n\n">>, "\"\\n\\n\\n\""}, + {<<"\" \b\f\r\n\t\"">>, "\"\\\" \\b\\f\\r\\n\\t\\\"\""}, + {obj_new(), "{}"}, + {obj_from_list([{<<"foo">>, <<"bar">>}]), "{\"foo\":\"bar\"}"}, + {obj_from_list([{<<"foo">>, <<"bar">>}, {<<"baz">>, 123}]), + "{\"foo\":\"bar\",\"baz\":123}"}, + {[], "[]"}, + {[[]], "[[]]"}, + {[1, <<"foo">>], "[1,\"foo\"]"}, + + %% json array in a json object + {obj_from_list([{<<"foo">>, [123]}]), + "{\"foo\":[123]}"}, + + %% json object in a json object + {obj_from_list([{<<"foo">>, obj_from_list([{<<"bar">>, true}])}]), + "{\"foo\":{\"bar\":true}}"}, + + %% fold evaluation order + {obj_from_list([{<<"foo">>, []}, + {<<"bar">>, obj_from_list([{<<"baz">>, true}])}, + {<<"alice">>, <<"bob">>}]), + "{\"foo\":[],\"bar\":{\"baz\":true},\"alice\":\"bob\"}"}, + + %% json object in a json array + {[-123, <<"foo">>, obj_from_list([{<<"bar">>, []}]), null], + "[-123,\"foo\",{\"bar\":[]},null]"} + ]. + +%% test utf8 encoding +encoder_utf8_test() -> + %% safe conversion case (default) + <<"\"\\u0001\\u0442\\u0435\\u0441\\u0442\"">> = + iolist_to_binary(encode(<<1,"\321\202\320\265\321\201\321\202">>)), + + %% raw utf8 output (optional) + Enc = mochijson2:encoder([{utf8, true}]), + <<34,"\\u0001",209,130,208,181,209,129,209,130,34>> = + iolist_to_binary(Enc(<<1,"\321\202\320\265\321\201\321\202">>)). + +input_validation_test() -> + Good = [ + {16#00A3, <>}, %% pound + {16#20AC, <>}, %% euro + {16#10196, <>} %% denarius + ], + lists:foreach(fun({CodePoint, UTF8}) -> + Expect = unicode:characters_to_binary([CodePoint]), + Expect = decode(UTF8) + end, Good), + + Bad = [ + %% 2nd, 3rd, or 4th byte of a multi-byte sequence w/o leading byte + <>, + %% missing continuations, last byte in each should be 80-BF + <>, + <>, + <>, + %% we don't support code points > 10FFFF per RFC 3629 + <>, + %% escape characters trigger a different code path + <> + ], + lists:foreach( + fun(X) -> + ok = try decode(X) catch invalid_utf8 -> ok end, + %% could be {ucs,{bad_utf8_character_code}} or + %% {json_encode,{bad_char,_}} + {'EXIT', _} = (catch encode(X)) + end, Bad). + +inline_json_test() -> + ?assertEqual(<<"\"iodata iodata\"">>, + iolist_to_binary( + encode({json, [<<"\"iodata">>, " iodata\""]}))), + ?assertEqual({struct, [{<<"key">>, <<"iodata iodata">>}]}, + decode( + encode({struct, + [{key, {json, [<<"\"iodata">>, " iodata\""]}}]}))), + ok. + +big_unicode_test() -> + UTF8Seq = unicode:characters_to_binary([16#0001d120]), + ?assertEqual( + <<"\"\\ud834\\udd20\"">>, + iolist_to_binary(encode(UTF8Seq))), + ?assertEqual( + UTF8Seq, + decode(iolist_to_binary(encode(UTF8Seq)))), + ok. + +custom_decoder_test() -> + ?assertEqual( + {struct, [{<<"key">>, <<"value">>}]}, + (decoder([]))("{\"key\": \"value\"}")), + F = fun ({struct, [{<<"key">>, <<"value">>}]}) -> win end, + ?assertEqual( + win, + (decoder([{object_hook, F}]))("{\"key\": \"value\"}")), + ok. + +atom_test() -> + %% JSON native atoms + [begin + ?assertEqual(A, decode(atom_to_list(A))), + ?assertEqual(iolist_to_binary(atom_to_list(A)), + iolist_to_binary(encode(A))) + end || A <- [true, false, null]], + %% Atom to string + ?assertEqual( + <<"\"foo\"">>, + iolist_to_binary(encode(foo))), + ?assertEqual( + <<"\"\\ud834\\udd20\"">>, + iolist_to_binary( + encode( + binary_to_atom( + unicode:characters_to_binary([16#0001d120]), latin1)))), + ok. + +key_encode_test() -> + %% Some forms are accepted as keys that would not be strings in other + %% cases + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode({struct, [{foo, 1}]}))), + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode({struct, [{<<"foo">>, 1}]}))), + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode({struct, [{"foo", 1}]}))), + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode([{foo, 1}]))), + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode([{<<"foo">>, 1}]))), + ?assertEqual( + <<"{\"foo\":1}">>, + iolist_to_binary(encode([{"foo", 1}]))), + ?assertEqual( + <<"{\"\\ud834\\udd20\":1}">>, + iolist_to_binary( + encode({struct, [{[16#0001d120], 1}]}))), + ?assertEqual( + <<"{\"1\":1}">>, + iolist_to_binary(encode({struct, [{1, 1}]}))), + ok. + +unsafe_chars_test() -> + Chars = "\"\\\b\f\n\r\t", + [begin + ?assertEqual(false, json_string_is_safe([C])), + ?assertEqual(false, json_bin_is_safe(<>)), + ?assertEqual(<>, decode(encode(<>))) + end || C <- Chars], + ?assertEqual( + false, + json_string_is_safe([16#0001d120])), + ?assertEqual( + false, + json_bin_is_safe(unicode:characters_to_binary([16#0001d120]))), + ?assertEqual( + [16#0001d120], + unicode:characters_to_list( + decode( + encode( + binary_to_atom( + unicode:characters_to_binary([16#0001d120]), + latin1))))), + ?assertEqual( + false, + json_string_is_safe([16#10ffff])), + ?assertEqual( + false, + json_bin_is_safe(unicode:characters_to_binary([16#10ffff]))), + %% solidus can be escaped but isn't unsafe by default + ?assertEqual( + <<"/">>, + decode(<<"\"\\/\"">>)), + ok. + +int_test() -> + ?assertEqual(0, decode("0")), + ?assertEqual(1, decode("1")), + ?assertEqual(11, decode("11")), + ok. + +large_int_test() -> + ?assertEqual(<<"-2147483649214748364921474836492147483649">>, + iolist_to_binary(encode(-2147483649214748364921474836492147483649))), + ?assertEqual(<<"2147483649214748364921474836492147483649">>, + iolist_to_binary(encode(2147483649214748364921474836492147483649))), + ok. + +float_test() -> + ?assertEqual(<<"-2147483649.0">>, iolist_to_binary(encode(-2147483649.0))), + ?assertEqual(<<"2147483648.0">>, iolist_to_binary(encode(2147483648.0))), + ok. + +handler_test() -> + ?assertEqual( + {'EXIT',{json_encode,{bad_term,{x,y}}}}, + catch encode({x,y})), + F = fun ({x,y}) -> [] end, + ?assertEqual( + <<"[]">>, + iolist_to_binary((encoder([{handler, F}]))({x, y}))), + ok. + +encode_empty_test_() -> + [{A, ?_assertEqual(<<"{}">>, iolist_to_binary(encode(B)))} + || {A, B} <- [{"eep18 {}", {}}, + {"eep18 {[]}", {[]}}, + {"{struct, []}", {struct, []}}]]. + +encode_test_() -> + P = [{<<"k">>, <<"v">>}], + JSON = iolist_to_binary(encode({struct, P})), + [{atom_to_list(F), + ?_assertEqual(JSON, iolist_to_binary(encode(decode(JSON, [{format, F}]))))} + || F <- [struct, eep18, proplist]]. + +format_test_() -> + P = [{<<"k">>, <<"v">>}], + JSON = iolist_to_binary(encode({struct, P})), + [{atom_to_list(F), + ?_assertEqual(A, decode(JSON, [{format, F}]))} + || {F, A} <- [{struct, {struct, P}}, + {eep18, {P}}, + {proplist, P}]]. + +array_test() -> + A = [<<"hello">>], + ?assertEqual(A, decode(encode({array, A}))). + +bad_char_test() -> + ?assertEqual( + {'EXIT', {json_encode, {bad_char, 16#110000}}}, + catch json_string_is_safe([16#110000])). + +utf8_roundtrip_test_() -> + %% These are the boundary cases for UTF8 encoding + Codepoints = [%% 7 bits -> 1 byte + 16#00, 16#7f, + %% 11 bits -> 2 bytes + 16#080, 16#07ff, + %% 16 bits -> 3 bytes + 16#0800, 16#ffff, + 16#d7ff, 16#e000, + %% 21 bits -> 4 bytes + 16#010000, 16#10ffff], + UTF8 = unicode:characters_to_binary(Codepoints), + Encode = encoder([{utf8, true}]), + [{"roundtrip escaped", + ?_assertEqual(UTF8, decode(encode(UTF8)))}, + {"roundtrip utf8", + ?_assertEqual(UTF8, decode(Encode(UTF8)))}]. + +utf8_non_character_test_() -> + S = unicode:characters_to_binary([16#ffff, 16#fffe]), + [{"roundtrip escaped", ?_assertEqual(S, decode(encode(S)))}, + {"roundtrip utf8", ?_assertEqual(S, decode((encoder([{utf8, true}]))(S)))}]. + +-endif. diff --git a/deps/mochiweb/src/mochilists.erl b/deps/mochiweb/src/mochilists.erl new file mode 100644 index 0000000..24fa2f3 --- /dev/null +++ b/deps/mochiweb/src/mochilists.erl @@ -0,0 +1,122 @@ +%% @copyright Copyright (c) 2010 Mochi Media, Inc. +%% @author David Reid +%% +%% 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. + +%% @doc Utility functions for dealing with proplists. + +-module(mochilists). +-author("David Reid "). +-export([get_value/2, get_value/3, is_defined/2, set_default/2, set_defaults/2]). + +%% @spec set_default({Key::term(), Value::term()}, Proplist::list()) -> list() +%% +%% @doc Return new Proplist with {Key, Value} set if not is_defined(Key, Proplist). +set_default({Key, Value}, Proplist) -> + case is_defined(Key, Proplist) of + true -> + Proplist; + false -> + [{Key, Value} | Proplist] + end. + +%% @spec set_defaults([{Key::term(), Value::term()}], Proplist::list()) -> list() +%% +%% @doc Return new Proplist with {Key, Value} set if not is_defined(Key, Proplist). +set_defaults(DefaultProps, Proplist) -> + lists:foldl(fun set_default/2, Proplist, DefaultProps). + + +%% @spec is_defined(Key::term(), Proplist::list()) -> bool() +%% +%% @doc Returns true if Propist contains at least one entry associated +%% with Key, otherwise false is returned. +is_defined(Key, Proplist) -> + lists:keyfind(Key, 1, Proplist) =/= false. + + +%% @spec get_value(Key::term(), Proplist::list()) -> term() | undefined +%% +%% @doc Return the value of Key or undefined +get_value(Key, Proplist) -> + get_value(Key, Proplist, undefined). + +%% @spec get_value(Key::term(), Proplist::list(), Default::term()) -> term() +%% +%% @doc Return the value of Key or Default +get_value(_Key, [], Default) -> + Default; +get_value(Key, Proplist, Default) -> + case lists:keyfind(Key, 1, Proplist) of + false -> + Default; + {Key, Value} -> + Value + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +set_defaults_test() -> + ?assertEqual( + [{k, v}], + set_defaults([{k, v}], [])), + ?assertEqual( + [{k, v}], + set_defaults([{k, vee}], [{k, v}])), + ?assertEqual( + lists:sort([{kay, vee}, {k, v}]), + lists:sort(set_defaults([{k, vee}, {kay, vee}], [{k, v}]))), + ok. + +set_default_test() -> + ?assertEqual( + [{k, v}], + set_default({k, v}, [])), + ?assertEqual( + [{k, v}], + set_default({k, vee}, [{k, v}])), + ok. + +get_value_test() -> + ?assertEqual( + undefined, + get_value(foo, [])), + ?assertEqual( + undefined, + get_value(foo, [{bar, baz}])), + ?assertEqual( + bar, + get_value(foo, [{foo, bar}])), + ?assertEqual( + default, + get_value(foo, [], default)), + ?assertEqual( + default, + get_value(foo, [{bar, baz}], default)), + ?assertEqual( + bar, + get_value(foo, [{foo, bar}], default)), + ok. + +-endif. + diff --git a/deps/mochiweb/src/mochilogfile2.erl b/deps/mochiweb/src/mochilogfile2.erl new file mode 100644 index 0000000..6ff8fec --- /dev/null +++ b/deps/mochiweb/src/mochilogfile2.erl @@ -0,0 +1,158 @@ +%% @author Bob Ippolito +%% @copyright 2010 Mochi Media, Inc. +%% +%% 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. + +%% @doc Write newline delimited log files, ensuring that if a truncated +%% entry is found on log open then it is fixed before writing. Uses +%% delayed writes and raw files for performance. +-module(mochilogfile2). +-author('bob@mochimedia.com'). + +-export([open/1, write/2, close/1, name/1]). + +%% @spec open(Name) -> Handle +%% @doc Open the log file Name, creating or appending as necessary. All data +%% at the end of the file will be truncated until a newline is found, to +%% ensure that all records are complete. +open(Name) -> + {ok, FD} = file:open(Name, [raw, read, write, delayed_write, binary]), + fix_log(FD), + {?MODULE, Name, FD}. + +%% @spec name(Handle) -> string() +%% @doc Return the path of the log file. +name({?MODULE, Name, _FD}) -> + Name. + +%% @spec write(Handle, IoData) -> ok +%% @doc Write IoData to the log file referenced by Handle. +write({?MODULE, _Name, FD}, IoData) -> + ok = file:write(FD, [IoData, $\n]), + ok. + +%% @spec close(Handle) -> ok +%% @doc Close the log file referenced by Handle. +close({?MODULE, _Name, FD}) -> + ok = file:sync(FD), + ok = file:close(FD), + ok. + +fix_log(FD) -> + {ok, Location} = file:position(FD, eof), + Seek = find_last_newline(FD, Location), + {ok, Seek} = file:position(FD, Seek), + ok = file:truncate(FD), + ok. + +%% Seek backwards to the last valid log entry +find_last_newline(_FD, N) when N =< 1 -> + 0; +find_last_newline(FD, Location) -> + case file:pread(FD, Location - 1, 1) of + {ok, <<$\n>>} -> + Location; + {ok, _} -> + find_last_newline(FD, Location - 1) + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +name_test() -> + D = mochitemp:mkdtemp(), + FileName = filename:join(D, "open_close_test.log"), + H = open(FileName), + ?assertEqual( + FileName, + name(H)), + close(H), + file:delete(FileName), + file:del_dir(D), + ok. + +open_close_test() -> + D = mochitemp:mkdtemp(), + FileName = filename:join(D, "open_close_test.log"), + OpenClose = fun () -> + H = open(FileName), + ?assertEqual( + true, + filelib:is_file(FileName)), + ok = close(H), + ?assertEqual( + {ok, <<>>}, + file:read_file(FileName)), + ok + end, + OpenClose(), + OpenClose(), + file:delete(FileName), + file:del_dir(D), + ok. + +write_test() -> + D = mochitemp:mkdtemp(), + FileName = filename:join(D, "write_test.log"), + F = fun () -> + H = open(FileName), + write(H, "test line"), + close(H), + ok + end, + F(), + ?assertEqual( + {ok, <<"test line\n">>}, + file:read_file(FileName)), + F(), + ?assertEqual( + {ok, <<"test line\ntest line\n">>}, + file:read_file(FileName)), + file:delete(FileName), + file:del_dir(D), + ok. + +fix_log_test() -> + D = mochitemp:mkdtemp(), + FileName = filename:join(D, "write_test.log"), + file:write_file(FileName, <<"first line good\nsecond line bad">>), + F = fun () -> + H = open(FileName), + write(H, "test line"), + close(H), + ok + end, + F(), + ?assertEqual( + {ok, <<"first line good\ntest line\n">>}, + file:read_file(FileName)), + file:write_file(FileName, <<"first line bad">>), + F(), + ?assertEqual( + {ok, <<"test line\n">>}, + file:read_file(FileName)), + F(), + ?assertEqual( + {ok, <<"test line\ntest line\n">>}, + file:read_file(FileName)), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochinum.erl b/deps/mochiweb/src/mochinum.erl new file mode 100644 index 0000000..d687370 --- /dev/null +++ b/deps/mochiweb/src/mochinum.erl @@ -0,0 +1,372 @@ +%% @copyright 2007 Mochi Media, Inc. +%% @author Bob Ippolito +%% +%% 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. + +%% @doc Useful numeric algorithms for floats that cover some deficiencies +%% in the math module. More interesting is digits/1, which implements +%% the algorithm from: +%% http://www.cs.indiana.edu/~burger/fp/index.html +%% See also "Printing Floating-Point Numbers Quickly and Accurately" +%% in Proceedings of the SIGPLAN '96 Conference on Programming Language +%% Design and Implementation. + +-module(mochinum). +-author("Bob Ippolito "). +-export([digits/1, frexp/1, int_pow/2, int_ceil/1]). + +%% IEEE 754 Float exponent bias +-define(FLOAT_BIAS, 1022). +-define(MIN_EXP, -1074). +-define(BIG_POW, 4503599627370496). + +%% External API + +%% @spec digits(number()) -> string() +%% @doc Returns a string that accurately represents the given integer or float +%% using a conservative amount of digits. Great for generating +%% human-readable output, or compact ASCII serializations for floats. +digits(N) when is_integer(N) -> + integer_to_list(N); +digits(0.0) -> + "0.0"; +digits(Float) -> + {Frac1, Exp1} = frexp_int(Float), + [Place0 | Digits0] = digits1(Float, Exp1, Frac1), + {Place, Digits} = transform_digits(Place0, Digits0), + R = insert_decimal(Place, Digits), + case Float < 0 of + true -> + [$- | R]; + _ -> + R + end. + +%% @spec frexp(F::float()) -> {Frac::float(), Exp::float()} +%% @doc Return the fractional and exponent part of an IEEE 754 double, +%% equivalent to the libc function of the same name. +%% F = Frac * pow(2, Exp). +frexp(F) -> + frexp1(unpack(F)). + +%% @spec int_pow(X::integer(), N::integer()) -> Y::integer() +%% @doc Moderately efficient way to exponentiate integers. +%% int_pow(10, 2) = 100. +int_pow(_X, 0) -> + 1; +int_pow(X, N) when N > 0 -> + int_pow(X, N, 1). + +%% @spec int_ceil(F::float()) -> integer() +%% @doc Return the ceiling of F as an integer. The ceiling is defined as +%% F when F == trunc(F); +%% trunc(F) when F < 0; +%% trunc(F) + 1 when F > 0. +int_ceil(X) -> + T = trunc(X), + case (X - T) of + Pos when Pos > 0 -> T + 1; + _ -> T + end. + + +%% Internal API + +int_pow(X, N, R) when N < 2 -> + R * X; +int_pow(X, N, R) -> + int_pow(X * X, N bsr 1, case N band 1 of 1 -> R * X; 0 -> R end). + +insert_decimal(0, S) -> + "0." ++ S; +insert_decimal(Place, S) when Place > 0 -> + L = length(S), + case Place - L of + 0 -> + S ++ ".0"; + N when N < 0 -> + {S0, S1} = lists:split(L + N, S), + S0 ++ "." ++ S1; + N when N < 6 -> + %% More places than digits + S ++ lists:duplicate(N, $0) ++ ".0"; + _ -> + insert_decimal_exp(Place, S) + end; +insert_decimal(Place, S) when Place > -6 -> + "0." ++ lists:duplicate(abs(Place), $0) ++ S; +insert_decimal(Place, S) -> + insert_decimal_exp(Place, S). + +insert_decimal_exp(Place, S) -> + [C | S0] = S, + S1 = case S0 of + [] -> + "0"; + _ -> + S0 + end, + Exp = case Place < 0 of + true -> + "e-"; + false -> + "e+" + end, + [C] ++ "." ++ S1 ++ Exp ++ integer_to_list(abs(Place - 1)). + + +digits1(Float, Exp, Frac) -> + Round = ((Frac band 1) =:= 0), + case Exp >= 0 of + true -> + BExp = 1 bsl Exp, + case (Frac =/= ?BIG_POW) of + true -> + scale((Frac * BExp * 2), 2, BExp, BExp, + Round, Round, Float); + false -> + scale((Frac * BExp * 4), 4, (BExp * 2), BExp, + Round, Round, Float) + end; + false -> + case (Exp =:= ?MIN_EXP) orelse (Frac =/= ?BIG_POW) of + true -> + scale((Frac * 2), 1 bsl (1 - Exp), 1, 1, + Round, Round, Float); + false -> + scale((Frac * 4), 1 bsl (2 - Exp), 2, 1, + Round, Round, Float) + end + end. + +scale(R, S, MPlus, MMinus, LowOk, HighOk, Float) -> + Est = int_ceil(math:log10(abs(Float)) - 1.0e-10), + %% Note that the scheme implementation uses a 326 element look-up table + %% for int_pow(10, N) where we do not. + case Est >= 0 of + true -> + fixup(R, S * int_pow(10, Est), MPlus, MMinus, Est, + LowOk, HighOk); + false -> + Scale = int_pow(10, -Est), + fixup(R * Scale, S, MPlus * Scale, MMinus * Scale, Est, + LowOk, HighOk) + end. + +fixup(R, S, MPlus, MMinus, K, LowOk, HighOk) -> + TooLow = case HighOk of + true -> + (R + MPlus) >= S; + false -> + (R + MPlus) > S + end, + case TooLow of + true -> + [(K + 1) | generate(R, S, MPlus, MMinus, LowOk, HighOk)]; + false -> + [K | generate(R * 10, S, MPlus * 10, MMinus * 10, LowOk, HighOk)] + end. + +generate(R0, S, MPlus, MMinus, LowOk, HighOk) -> + D = R0 div S, + R = R0 rem S, + TC1 = case LowOk of + true -> + R =< MMinus; + false -> + R < MMinus + end, + TC2 = case HighOk of + true -> + (R + MPlus) >= S; + false -> + (R + MPlus) > S + end, + case TC1 of + false -> + case TC2 of + false -> + [D | generate(R * 10, S, MPlus * 10, MMinus * 10, + LowOk, HighOk)]; + true -> + [D + 1] + end; + true -> + case TC2 of + false -> + [D]; + true -> + case R * 2 < S of + true -> + [D]; + false -> + [D + 1] + end + end + end. + +unpack(Float) -> + <> = <>, + {Sign, Exp, Frac}. + +frexp1({_Sign, 0, 0}) -> + {0.0, 0}; +frexp1({Sign, 0, Frac}) -> + Exp = log2floor(Frac), + <> = <>, + {Frac1, -(?FLOAT_BIAS) - 52 + Exp}; +frexp1({Sign, Exp, Frac}) -> + <> = <>, + {Frac1, Exp - ?FLOAT_BIAS}. + +log2floor(Int) -> + log2floor(Int, 0). + +log2floor(0, N) -> + N; +log2floor(Int, N) -> + log2floor(Int bsr 1, 1 + N). + + +transform_digits(Place, [0 | Rest]) -> + transform_digits(Place, Rest); +transform_digits(Place, Digits) -> + {Place, [$0 + D || D <- Digits]}. + + +frexp_int(F) -> + case unpack(F) of + {_Sign, 0, Frac} -> + {Frac, ?MIN_EXP}; + {_Sign, Exp, Frac} -> + {Frac + (1 bsl 52), Exp - 53 - ?FLOAT_BIAS} + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +int_ceil_test() -> + ?assertEqual(1, int_ceil(0.0001)), + ?assertEqual(0, int_ceil(0.0)), + ?assertEqual(1, int_ceil(0.99)), + ?assertEqual(1, int_ceil(1.0)), + ?assertEqual(-1, int_ceil(-1.5)), + ?assertEqual(-2, int_ceil(-2.0)), + ok. + +int_pow_test() -> + ?assertEqual(1, int_pow(1, 1)), + ?assertEqual(1, int_pow(1, 0)), + ?assertEqual(1, int_pow(10, 0)), + ?assertEqual(10, int_pow(10, 1)), + ?assertEqual(100, int_pow(10, 2)), + ?assertEqual(1000, int_pow(10, 3)), + ok. + +digits_test() -> + ?assertEqual("0", + digits(0)), + ?assertEqual("0.0", + digits(0.0)), + ?assertEqual("1.0", + digits(1.0)), + ?assertEqual("-1.0", + digits(-1.0)), + ?assertEqual("0.1", + digits(0.1)), + ?assertEqual("0.01", + digits(0.01)), + ?assertEqual("0.001", + digits(0.001)), + ?assertEqual("1.0e+6", + digits(1000000.0)), + ?assertEqual("0.5", + digits(0.5)), + ?assertEqual("4503599627370496.0", + digits(4503599627370496.0)), + %% small denormalized number + %% 4.94065645841246544177e-324 =:= 5.0e-324 + <> = <<0,0,0,0,0,0,0,1>>, + ?assertEqual("5.0e-324", + digits(SmallDenorm)), + ?assertEqual(SmallDenorm, + list_to_float(digits(SmallDenorm))), + %% large denormalized number + %% 2.22507385850720088902e-308 + <> = <<0,15,255,255,255,255,255,255>>, + ?assertEqual("2.225073858507201e-308", + digits(BigDenorm)), + ?assertEqual(BigDenorm, + list_to_float(digits(BigDenorm))), + %% small normalized number + %% 2.22507385850720138309e-308 + <> = <<0,16,0,0,0,0,0,0>>, + ?assertEqual("2.2250738585072014e-308", + digits(SmallNorm)), + ?assertEqual(SmallNorm, + list_to_float(digits(SmallNorm))), + %% large normalized number + %% 1.79769313486231570815e+308 + <> = <<127,239,255,255,255,255,255,255>>, + ?assertEqual("1.7976931348623157e+308", + digits(LargeNorm)), + ?assertEqual(LargeNorm, + list_to_float(digits(LargeNorm))), + %% issue #10 - mochinum:frexp(math:pow(2, -1074)). + ?assertEqual("5.0e-324", + digits(math:pow(2, -1074))), + ok. + +frexp_test() -> + %% zero + ?assertEqual({0.0, 0}, frexp(0.0)), + %% one + ?assertEqual({0.5, 1}, frexp(1.0)), + %% negative one + ?assertEqual({-0.5, 1}, frexp(-1.0)), + %% small denormalized number + %% 4.94065645841246544177e-324 + <> = <<0,0,0,0,0,0,0,1>>, + ?assertEqual({0.5, -1073}, frexp(SmallDenorm)), + %% large denormalized number + %% 2.22507385850720088902e-308 + <> = <<0,15,255,255,255,255,255,255>>, + ?assertEqual( + {0.99999999999999978, -1022}, + frexp(BigDenorm)), + %% small normalized number + %% 2.22507385850720138309e-308 + <> = <<0,16,0,0,0,0,0,0>>, + ?assertEqual({0.5, -1021}, frexp(SmallNorm)), + %% large normalized number + %% 1.79769313486231570815e+308 + <> = <<127,239,255,255,255,255,255,255>>, + ?assertEqual( + {0.99999999999999989, 1024}, + frexp(LargeNorm)), + %% issue #10 - mochinum:frexp(math:pow(2, -1074)). + ?assertEqual( + {0.5, -1073}, + frexp(math:pow(2, -1074))), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochitemp.erl b/deps/mochiweb/src/mochitemp.erl new file mode 100644 index 0000000..bd3c965 --- /dev/null +++ b/deps/mochiweb/src/mochitemp.erl @@ -0,0 +1,329 @@ +%% @author Bob Ippolito +%% @copyright 2010 Mochi Media, Inc. +%% +%% 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. + +%% @doc Create temporary files and directories. Requires crypto to be started. + +-module(mochitemp). +-export([gettempdir/0]). +-export([mkdtemp/0, mkdtemp/3]). +-export([rmtempdir/1]). +%% -export([mkstemp/4]). +-define(SAFE_CHARS, {$a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, + $n, $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, + $A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, + $N, $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, + $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $_}). +-define(TMP_MAX, 10000). + +-include_lib("kernel/include/file.hrl"). + +%% TODO: An ugly wrapper over the mktemp tool with open_port and sadness? +%% We can't implement this race-free in Erlang without the ability +%% to issue O_CREAT|O_EXCL. I suppose we could hack something with +%% mkdtemp, del_dir, open. +%% mkstemp(Suffix, Prefix, Dir, Options) -> +%% ok. + +rmtempdir(Dir) -> + case file:del_dir(Dir) of + {error, eexist} -> + ok = rmtempdirfiles(Dir), + ok = file:del_dir(Dir); + ok -> + ok + end. + +rmtempdirfiles(Dir) -> + {ok, Files} = file:list_dir(Dir), + ok = rmtempdirfiles(Dir, Files). + +rmtempdirfiles(_Dir, []) -> + ok; +rmtempdirfiles(Dir, [Basename | Rest]) -> + Path = filename:join([Dir, Basename]), + case filelib:is_dir(Path) of + true -> + ok = rmtempdir(Path); + false -> + ok = file:delete(Path) + end, + rmtempdirfiles(Dir, Rest). + +mkdtemp() -> + mkdtemp("", "tmp", gettempdir()). + +mkdtemp(Suffix, Prefix, Dir) -> + mkdtemp_n(rngpath_fun(Suffix, Prefix, Dir), ?TMP_MAX). + + + +mkdtemp_n(RngPath, 1) -> + make_dir(RngPath()); +mkdtemp_n(RngPath, N) -> + try make_dir(RngPath()) + catch throw:{error, eexist} -> + mkdtemp_n(RngPath, N - 1) + end. + +make_dir(Path) -> + case file:make_dir(Path) of + ok -> + ok; + E={error, eexist} -> + throw(E) + end, + %% Small window for a race condition here because dir is created 777 + ok = file:write_file_info(Path, #file_info{mode=8#0700}), + Path. + +rngpath_fun(Prefix, Suffix, Dir) -> + fun () -> + filename:join([Dir, Prefix ++ rngchars(6) ++ Suffix]) + end. + +rngchars(0) -> + ""; +rngchars(N) -> + [rngchar() | rngchars(N - 1)]. + +rngchar() -> + rngchar(crypto:rand_uniform(0, tuple_size(?SAFE_CHARS))). + +rngchar(C) -> + element(1 + C, ?SAFE_CHARS). + +%% @spec gettempdir() -> string() +%% @doc Get a usable temporary directory using the first of these that is a directory: +%% $TMPDIR, $TMP, $TEMP, "/tmp", "/var/tmp", "/usr/tmp", ".". +gettempdir() -> + gettempdir(gettempdir_checks(), fun normalize_dir/1). + +gettempdir_checks() -> + [{fun os:getenv/1, ["TMPDIR", "TMP", "TEMP"]}, + {fun gettempdir_identity/1, ["/tmp", "/var/tmp", "/usr/tmp"]}, + {fun gettempdir_cwd/1, [cwd]}]. + +gettempdir_identity(L) -> + L. + +gettempdir_cwd(cwd) -> + {ok, L} = file:get_cwd(), + L. + +gettempdir([{_F, []} | RestF], Normalize) -> + gettempdir(RestF, Normalize); +gettempdir([{F, [L | RestL]} | RestF], Normalize) -> + case Normalize(F(L)) of + false -> + gettempdir([{F, RestL} | RestF], Normalize); + Dir -> + Dir + end. + +normalize_dir(False) when False =:= false orelse False =:= "" -> + %% Erlang doesn't have an unsetenv, wtf. + false; +normalize_dir(L) -> + Dir = filename:absname(L), + case filelib:is_dir(Dir) of + false -> + false; + true -> + Dir + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +pushenv(L) -> + [{K, os:getenv(K)} || K <- L]. +popenv(L) -> + F = fun ({K, false}) -> + %% Erlang doesn't have an unsetenv, wtf. + os:putenv(K, ""); + ({K, V}) -> + os:putenv(K, V) + end, + lists:foreach(F, L). + +gettempdir_fallback_test() -> + ?assertEqual( + "/", + gettempdir([{fun gettempdir_identity/1, ["/--not-here--/"]}, + {fun gettempdir_identity/1, ["/"]}], + fun normalize_dir/1)), + ?assertEqual( + "/", + %% simulate a true os:getenv unset env + gettempdir([{fun gettempdir_identity/1, [false]}, + {fun gettempdir_identity/1, ["/"]}], + fun normalize_dir/1)), + ok. + +gettempdir_identity_test() -> + ?assertEqual( + "/", + gettempdir([{fun gettempdir_identity/1, ["/"]}], fun normalize_dir/1)), + ok. + +gettempdir_cwd_test() -> + {ok, Cwd} = file:get_cwd(), + ?assertEqual( + normalize_dir(Cwd), + gettempdir([{fun gettempdir_cwd/1, [cwd]}], fun normalize_dir/1)), + ok. + +rngchars_test() -> + crypto:start(), + ?assertEqual( + "", + rngchars(0)), + ?assertEqual( + 10, + length(rngchars(10))), + ok. + +rngchar_test() -> + ?assertEqual( + $a, + rngchar(0)), + ?assertEqual( + $A, + rngchar(26)), + ?assertEqual( + $_, + rngchar(62)), + ok. + +mkdtemp_n_failonce_test() -> + crypto:start(), + D = mkdtemp(), + Path = filename:join([D, "testdir"]), + %% Toggle the existence of a dir so that it fails + %% the first time and succeeds the second. + F = fun () -> + case filelib:is_dir(Path) of + true -> + file:del_dir(Path); + false -> + file:make_dir(Path) + end, + Path + end, + try + %% Fails the first time + ?assertThrow( + {error, eexist}, + mkdtemp_n(F, 1)), + %% Reset state + file:del_dir(Path), + %% Succeeds the second time + ?assertEqual( + Path, + mkdtemp_n(F, 2)) + after rmtempdir(D) + end, + ok. + +mkdtemp_n_fail_test() -> + {ok, Cwd} = file:get_cwd(), + ?assertThrow( + {error, eexist}, + mkdtemp_n(fun () -> Cwd end, 1)), + ?assertThrow( + {error, eexist}, + mkdtemp_n(fun () -> Cwd end, 2)), + ok. + +make_dir_fail_test() -> + {ok, Cwd} = file:get_cwd(), + ?assertThrow( + {error, eexist}, + make_dir(Cwd)), + ok. + +mkdtemp_test() -> + crypto:start(), + D = mkdtemp(), + ?assertEqual( + true, + filelib:is_dir(D)), + ?assertEqual( + ok, + file:del_dir(D)), + ok. + +rmtempdir_test() -> + crypto:start(), + D1 = mkdtemp(), + ?assertEqual( + true, + filelib:is_dir(D1)), + ?assertEqual( + ok, + rmtempdir(D1)), + D2 = mkdtemp(), + ?assertEqual( + true, + filelib:is_dir(D2)), + ok = file:write_file(filename:join([D2, "foo"]), <<"bytes">>), + D3 = mkdtemp("suffix", "prefix", D2), + ?assertEqual( + true, + filelib:is_dir(D3)), + ok = file:write_file(filename:join([D3, "foo"]), <<"bytes">>), + ?assertEqual( + ok, + rmtempdir(D2)), + ?assertEqual( + {error, enoent}, + file:consult(D3)), + ?assertEqual( + {error, enoent}, + file:consult(D2)), + ok. + +gettempdir_env_test() -> + Env = pushenv(["TMPDIR", "TEMP", "TMP"]), + FalseEnv = [{"TMPDIR", false}, {"TEMP", false}, {"TMP", false}], + try + popenv(FalseEnv), + popenv([{"TMPDIR", "/"}]), + ?assertEqual( + "/", + os:getenv("TMPDIR")), + ?assertEqual( + "/", + gettempdir()), + {ok, Cwd} = file:get_cwd(), + popenv(FalseEnv), + popenv([{"TMP", Cwd}]), + ?assertEqual( + normalize_dir(Cwd), + gettempdir()) + after popenv(Env) + end, + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiutf8.erl b/deps/mochiweb/src/mochiutf8.erl new file mode 100644 index 0000000..bf0e7cc --- /dev/null +++ b/deps/mochiweb/src/mochiutf8.erl @@ -0,0 +1,335 @@ +%% @copyright 2010 Mochi Media, Inc. +%% @author Bob Ippolito +%% +%% 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. + +%% @doc Algorithm to convert any binary to a valid UTF-8 sequence by ignoring +%% invalid bytes. + +-module(mochiutf8). +-export([valid_utf8_bytes/1, codepoint_to_bytes/1, codepoints_to_bytes/1]). +-export([bytes_to_codepoints/1, bytes_foldl/3, codepoint_foldl/3]). +-export([read_codepoint/1, len/1]). + +%% External API + +-type unichar_low() :: 0..16#d7ff. +-type unichar_high() :: 16#e000..16#10ffff. +-type unichar() :: unichar_low() | unichar_high(). + +-spec codepoint_to_bytes(unichar()) -> binary(). +%% @doc Convert a unicode codepoint to UTF-8 bytes. +codepoint_to_bytes(C) when (C >= 16#00 andalso C =< 16#7f) -> + %% U+0000 - U+007F - 7 bits + <>; +codepoint_to_bytes(C) when (C >= 16#080 andalso C =< 16#07FF) -> + %% U+0080 - U+07FF - 11 bits + <<0:5, B1:5, B0:6>> = <>, + <<2#110:3, B1:5, + 2#10:2, B0:6>>; +codepoint_to_bytes(C) when (C >= 16#0800 andalso C =< 16#FFFF) andalso + (C < 16#D800 orelse C > 16#DFFF) -> + %% U+0800 - U+FFFF - 16 bits (excluding UTC-16 surrogate code points) + <> = <>, + <<2#1110:4, B2:4, + 2#10:2, B1:6, + 2#10:2, B0:6>>; +codepoint_to_bytes(C) when (C >= 16#010000 andalso C =< 16#10FFFF) -> + %% U+10000 - U+10FFFF - 21 bits + <<0:3, B3:3, B2:6, B1:6, B0:6>> = <>, + <<2#11110:5, B3:3, + 2#10:2, B2:6, + 2#10:2, B1:6, + 2#10:2, B0:6>>. + +-spec codepoints_to_bytes([unichar()]) -> binary(). +%% @doc Convert a list of codepoints to a UTF-8 binary. +codepoints_to_bytes(L) -> + <<<<(codepoint_to_bytes(C))/binary>> || C <- L>>. + +-spec read_codepoint(binary()) -> {unichar(), binary(), binary()}. +read_codepoint(Bin = <<2#0:1, C:7, Rest/binary>>) -> + %% U+0000 - U+007F - 7 bits + <> = Bin, + {C, B, Rest}; +read_codepoint(Bin = <<2#110:3, B1:5, + 2#10:2, B0:6, + Rest/binary>>) -> + %% U+0080 - U+07FF - 11 bits + case <> of + <> when C >= 16#80 -> + <> = Bin, + {C, B, Rest} + end; +read_codepoint(Bin = <<2#1110:4, B2:4, + 2#10:2, B1:6, + 2#10:2, B0:6, + Rest/binary>>) -> + %% U+0800 - U+FFFF - 16 bits (excluding UTC-16 surrogate code points) + case <> of + <> when (C >= 16#0800 andalso C =< 16#FFFF) andalso + (C < 16#D800 orelse C > 16#DFFF) -> + <> = Bin, + {C, B, Rest} + end; +read_codepoint(Bin = <<2#11110:5, B3:3, + 2#10:2, B2:6, + 2#10:2, B1:6, + 2#10:2, B0:6, + Rest/binary>>) -> + %% U+10000 - U+10FFFF - 21 bits + case <> of + <> when (C >= 16#010000 andalso C =< 16#10FFFF) -> + <> = Bin, + {C, B, Rest} + end. + +-spec codepoint_foldl(fun((unichar(), _) -> _), _, binary()) -> _. +codepoint_foldl(F, Acc, <<>>) when is_function(F, 2) -> + Acc; +codepoint_foldl(F, Acc, Bin) -> + {C, _, Rest} = read_codepoint(Bin), + codepoint_foldl(F, F(C, Acc), Rest). + +-spec bytes_foldl(fun((binary(), _) -> _), _, binary()) -> _. +bytes_foldl(F, Acc, <<>>) when is_function(F, 2) -> + Acc; +bytes_foldl(F, Acc, Bin) -> + {_, B, Rest} = read_codepoint(Bin), + bytes_foldl(F, F(B, Acc), Rest). + +-spec bytes_to_codepoints(binary()) -> [unichar()]. +bytes_to_codepoints(B) -> + lists:reverse(codepoint_foldl(fun (C, Acc) -> [C | Acc] end, [], B)). + +-spec len(binary()) -> non_neg_integer(). +len(<<>>) -> + 0; +len(B) -> + {_, _, Rest} = read_codepoint(B), + 1 + len(Rest). + +-spec valid_utf8_bytes(B::binary()) -> binary(). +%% @doc Return only the bytes in B that represent valid UTF-8. Uses +%% the following recursive algorithm: skip one byte if B does not +%% follow UTF-8 syntax (a 1-4 byte encoding of some number), +%% skip sequence of 2-4 bytes if it represents an overlong encoding +%% or bad code point (surrogate U+D800 - U+DFFF or > U+10FFFF). +valid_utf8_bytes(B) when is_binary(B) -> + binary_skip_bytes(B, invalid_utf8_indexes(B)). + +%% Internal API + +-spec binary_skip_bytes(binary(), [non_neg_integer()]) -> binary(). +%% @doc Return B, but skipping the 0-based indexes in L. +binary_skip_bytes(B, []) -> + B; +binary_skip_bytes(B, L) -> + binary_skip_bytes(B, L, 0, []). + +%% @private +-spec binary_skip_bytes(binary(), [non_neg_integer()], non_neg_integer(), iolist()) -> binary(). +binary_skip_bytes(B, [], _N, Acc) -> + iolist_to_binary(lists:reverse([B | Acc])); +binary_skip_bytes(<<_, RestB/binary>>, [N | RestL], N, Acc) -> + binary_skip_bytes(RestB, RestL, 1 + N, Acc); +binary_skip_bytes(<>, L, N, Acc) -> + binary_skip_bytes(RestB, L, 1 + N, [C | Acc]). + +-spec invalid_utf8_indexes(binary()) -> [non_neg_integer()]. +%% @doc Return the 0-based indexes in B that are not valid UTF-8. +invalid_utf8_indexes(B) -> + invalid_utf8_indexes(B, 0, []). + +%% @private. +-spec invalid_utf8_indexes(binary(), non_neg_integer(), [non_neg_integer()]) -> [non_neg_integer()]. +invalid_utf8_indexes(<>, N, Acc) when C < 16#80 -> + %% U+0000 - U+007F - 7 bits + invalid_utf8_indexes(Rest, 1 + N, Acc); +invalid_utf8_indexes(<>, N, Acc) + when C1 band 16#E0 =:= 16#C0, + C2 band 16#C0 =:= 16#80 -> + %% U+0080 - U+07FF - 11 bits + case ((C1 band 16#1F) bsl 6) bor (C2 band 16#3F) of + C when C < 16#80 -> + %% Overlong encoding. + invalid_utf8_indexes(Rest, 2 + N, [1 + N, N | Acc]); + _ -> + %% Upper bound U+07FF does not need to be checked + invalid_utf8_indexes(Rest, 2 + N, Acc) + end; +invalid_utf8_indexes(<>, N, Acc) + when C1 band 16#F0 =:= 16#E0, + C2 band 16#C0 =:= 16#80, + C3 band 16#C0 =:= 16#80 -> + %% U+0800 - U+FFFF - 16 bits + case ((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor + (C3 band 16#3F) of + C when (C < 16#800) orelse (C >= 16#D800 andalso C =< 16#DFFF) -> + %% Overlong encoding or surrogate. + invalid_utf8_indexes(Rest, 3 + N, [2 + N, 1 + N, N | Acc]); + _ -> + %% Upper bound U+FFFF does not need to be checked + invalid_utf8_indexes(Rest, 3 + N, Acc) + end; +invalid_utf8_indexes(<>, N, Acc) + when C1 band 16#F8 =:= 16#F0, + C2 band 16#C0 =:= 16#80, + C3 band 16#C0 =:= 16#80, + C4 band 16#C0 =:= 16#80 -> + %% U+10000 - U+10FFFF - 21 bits + case ((((((C1 band 16#0F) bsl 6) bor (C2 band 16#3F)) bsl 6) bor + (C3 band 16#3F)) bsl 6) bor (C4 band 16#3F) of + C when (C < 16#10000) orelse (C > 16#10FFFF) -> + %% Overlong encoding or invalid code point. + invalid_utf8_indexes(Rest, 4 + N, [3 + N, 2 + N, 1 + N, N | Acc]); + _ -> + invalid_utf8_indexes(Rest, 4 + N, Acc) + end; +invalid_utf8_indexes(<<_, Rest/binary>>, N, Acc) -> + %% Invalid char + invalid_utf8_indexes(Rest, 1 + N, [N | Acc]); +invalid_utf8_indexes(<<>>, _N, Acc) -> + lists:reverse(Acc). + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +binary_skip_bytes_test() -> + ?assertEqual(<<"foo">>, + binary_skip_bytes(<<"foo">>, [])), + ?assertEqual(<<"foobar">>, + binary_skip_bytes(<<"foo bar">>, [3])), + ?assertEqual(<<"foo">>, + binary_skip_bytes(<<"foo bar">>, [3, 4, 5, 6])), + ?assertEqual(<<"oo bar">>, + binary_skip_bytes(<<"foo bar">>, [0])), + ok. + +invalid_utf8_indexes_test() -> + ?assertEqual( + [], + invalid_utf8_indexes(<<"unicode snowman for you: ", 226, 152, 131>>)), + ?assertEqual( + [0], + invalid_utf8_indexes(<<128>>)), + ?assertEqual( + [57,59,60,64,66,67], + invalid_utf8_indexes(<<"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (", + 167, 65, 170, 186, 73, 83, 80, 166, 87, 186, 217, 41, 41>>)), + ok. + +codepoint_to_bytes_test() -> + %% U+0000 - U+007F - 7 bits + %% U+0080 - U+07FF - 11 bits + %% U+0800 - U+FFFF - 16 bits (excluding UTC-16 surrogate code points) + %% U+10000 - U+10FFFF - 21 bits + ?assertEqual( + <<"a">>, + codepoint_to_bytes($a)), + ?assertEqual( + <<16#c2, 16#80>>, + codepoint_to_bytes(16#80)), + ?assertEqual( + <<16#df, 16#bf>>, + codepoint_to_bytes(16#07ff)), + ?assertEqual( + <<16#ef, 16#bf, 16#bf>>, + codepoint_to_bytes(16#ffff)), + ?assertEqual( + <<16#f4, 16#8f, 16#bf, 16#bf>>, + codepoint_to_bytes(16#10ffff)), + ok. + +bytes_foldl_test() -> + ?assertEqual( + <<"abc">>, + bytes_foldl(fun (B, Acc) -> <> end, <<>>, <<"abc">>)), + ?assertEqual( + <<"abc", 226, 152, 131, 228, 184, 173, 194, 133, 244,143,191,191>>, + bytes_foldl(fun (B, Acc) -> <> end, <<>>, + <<"abc", 226, 152, 131, 228, 184, 173, 194, 133, 244,143,191,191>>)), + ok. + +bytes_to_codepoints_test() -> + ?assertEqual( + "abc" ++ [16#2603, 16#4e2d, 16#85, 16#10ffff], + bytes_to_codepoints(<<"abc", 226, 152, 131, 228, 184, 173, 194, 133, 244,143,191,191>>)), + ok. + +codepoint_foldl_test() -> + ?assertEqual( + "cba", + codepoint_foldl(fun (C, Acc) -> [C | Acc] end, [], <<"abc">>)), + ?assertEqual( + [16#10ffff, 16#85, 16#4e2d, 16#2603 | "cba"], + codepoint_foldl(fun (C, Acc) -> [C | Acc] end, [], + <<"abc", 226, 152, 131, 228, 184, 173, 194, 133, 244,143,191,191>>)), + ok. + +len_test() -> + ?assertEqual( + 29, + len(<<"unicode snowman for you: ", 226, 152, 131, 228, 184, 173, 194, 133, 244, 143, 191, 191>>)), + ok. + +codepoints_to_bytes_test() -> + ?assertEqual( + iolist_to_binary(lists:map(fun codepoint_to_bytes/1, lists:seq(1, 1000))), + codepoints_to_bytes(lists:seq(1, 1000))), + ok. + +valid_utf8_bytes_test() -> + ?assertEqual( + <<"invalid U+11ffff: ">>, + valid_utf8_bytes(<<"invalid U+11ffff: ", 244, 159, 191, 191>>)), + ?assertEqual( + <<"U+10ffff: ", 244, 143, 191, 191>>, + valid_utf8_bytes(<<"U+10ffff: ", 244, 143, 191, 191>>)), + ?assertEqual( + <<"overlong 2-byte encoding (a): ">>, + valid_utf8_bytes(<<"overlong 2-byte encoding (a): ", 2#11000001, 2#10100001>>)), + ?assertEqual( + <<"overlong 2-byte encoding (!): ">>, + valid_utf8_bytes(<<"overlong 2-byte encoding (!): ", 2#11000000, 2#10100001>>)), + ?assertEqual( + <<"mu: ", 194, 181>>, + valid_utf8_bytes(<<"mu: ", 194, 181>>)), + ?assertEqual( + <<"bad coding bytes: ">>, + valid_utf8_bytes(<<"bad coding bytes: ", 2#10011111, 2#10111111, 2#11111111>>)), + ?assertEqual( + <<"low surrogate (unpaired): ">>, + valid_utf8_bytes(<<"low surrogate (unpaired): ", 237, 176, 128>>)), + ?assertEqual( + <<"high surrogate (unpaired): ">>, + valid_utf8_bytes(<<"high surrogate (unpaired): ", 237, 191, 191>>)), + ?assertEqual( + <<"unicode snowman for you: ", 226, 152, 131>>, + valid_utf8_bytes(<<"unicode snowman for you: ", 226, 152, 131>>)), + ?assertEqual( + <<"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (AISPW))">>, + valid_utf8_bytes(<<"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; (", + 167, 65, 170, 186, 73, 83, 80, 166, 87, 186, 217, 41, 41>>)), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiweb.app.src b/deps/mochiweb/src/mochiweb.app.src new file mode 100644 index 0000000..30fa905 --- /dev/null +++ b/deps/mochiweb/src/mochiweb.app.src @@ -0,0 +1,8 @@ +{application,mochiweb, + [{description,"MochiMedia Web Server"}, + {vsn,"2.13.1"}, + {modules,[]}, + {registered,[]}, + {env,[]}, + {applications,[kernel,stdlib,crypto,inets,ssl,xmerl,compiler, + syntax_tools]}]}. diff --git a/deps/mochiweb/src/mochiweb.erl b/deps/mochiweb/src/mochiweb.erl new file mode 100644 index 0000000..14480c2 --- /dev/null +++ b/deps/mochiweb/src/mochiweb.erl @@ -0,0 +1,101 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Start and stop the MochiWeb server. + +-module(mochiweb). +-author('bob@mochimedia.com'). + +-export([new_request/1, new_response/1]). +-export([all_loaded/0, all_loaded/1, reload/0]). +-export([ensure_started/1]). + +reload() -> + [c:l(Module) || Module <- all_loaded()]. + +all_loaded() -> + all_loaded(filename:dirname(code:which(?MODULE))). + +all_loaded(Base) when is_atom(Base) -> + []; +all_loaded(Base) -> + FullBase = Base ++ "/", + F = fun ({_Module, Loaded}, Acc) when is_atom(Loaded) -> + Acc; + ({Module, Loaded}, Acc) -> + case lists:prefix(FullBase, Loaded) of + true -> + [Module | Acc]; + false -> + Acc + end + end, + lists:foldl(F, [], code:all_loaded()). + +%% See the erlang:decode_packet/3 docs for the full type +-spec uri(HttpUri :: term()) -> string(). +uri({abs_path, Uri}) -> + Uri; +%% TODO: +%% This makes it hard to implement certain kinds of proxies with mochiweb, +%% perhaps a field could be added to the mochiweb_request record to preserve +%% this information in raw_path. +uri({absoluteURI, _Protocol, _Host, _Port, Uri}) -> + Uri; +%% From http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5.1.2 +uri('*') -> + "*"; +%% Erlang decode_packet will return this for requests like `CONNECT host:port` +uri({scheme, Hostname, Port}) -> + Hostname ++ ":" ++ Port; +uri(HttpString) when is_list(HttpString) -> + HttpString. + +%% @spec new_request( {Socket, Request, Headers} +%% | {Socket, Opts, Request, Headers} ) -> MochiWebRequest +%% @doc Return a mochiweb_request data structure. +new_request({Socket, {Method, HttpUri, Version}, Headers}) -> + new_request({Socket, [], {Method, HttpUri, Version}, Headers}); + +new_request({Socket, Opts, {Method, HttpUri, Version}, Headers}) -> + mochiweb_request:new(Socket, + Opts, + Method, + uri(HttpUri), + Version, + mochiweb_headers:make(Headers)). + +%% @spec new_response({Request, integer(), Headers}) -> MochiWebResponse +%% @doc Return a mochiweb_response data structure. +new_response({Request, Code, Headers}) -> + mochiweb_response:new(Request, + Code, + mochiweb_headers:make(Headers)). + +%% @spec ensure_started(App::atom()) -> ok +%% @doc Start the given App if it has not been started already. +ensure_started(App) -> + case application:start(App) of + ok -> + ok; + {error, {already_started, App}} -> + ok + end. diff --git a/deps/mochiweb/src/mochiweb_acceptor.erl b/deps/mochiweb/src/mochiweb_acceptor.erl new file mode 100644 index 0000000..44ce91f --- /dev/null +++ b/deps/mochiweb/src/mochiweb_acceptor.erl @@ -0,0 +1,83 @@ +%% @author Bob Ippolito +%% @copyright 2010 Mochi Media, Inc. +%% +%% 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. + +%% @doc MochiWeb acceptor. + +-module(mochiweb_acceptor). +-author('bob@mochimedia.com'). + +-include("internal.hrl"). + +-export([start_link/3, start_link/4, init/4]). + +-define(EMFILE_SLEEP_MSEC, 100). + +start_link(Server, Listen, Loop) -> + start_link(Server, Listen, Loop, []). + +start_link(Server, Listen, Loop, Opts) -> + proc_lib:spawn_link(?MODULE, init, [Server, Listen, Loop, Opts]). + +do_accept(Server, Listen) -> + T1 = os:timestamp(), + case mochiweb_socket:transport_accept(Listen) of + {ok, Socket} -> + gen_server:cast(Server, {accepted, self(), timer:now_diff(os:timestamp(), T1)}), + mochiweb_socket:finish_accept(Socket); + Other -> + Other + end. + +init(Server, Listen, Loop, Opts) -> + case catch do_accept(Server, Listen) of + {ok, Socket} -> + call_loop(Loop, Socket, Opts); + {error, Err} when Err =:= closed orelse + Err =:= esslaccept orelse + Err =:= timeout -> + exit(normal); + Other -> + %% Mitigate out of file descriptor scenario by sleeping for a + %% short time to slow error rate + case Other of + {error, emfile} -> + receive + after ?EMFILE_SLEEP_MSEC -> + ok + end; + _ -> + ok + end, + error_logger:error_report( + [{application, mochiweb}, + "Accept failed error", + lists:flatten(io_lib:format("~p", [Other]))]), + exit({error, accept_failed}) + end. + +call_loop({M, F}, Socket, Opts) -> + M:F(Socket, Opts); +call_loop({M, F, [A1]}, Socket, Opts) -> + M:F(Socket, Opts, A1); +call_loop({M, F, A}, Socket, Opts) -> + erlang:apply(M, F, [Socket, Opts | A]); +call_loop(Loop, Socket, Opts) -> + Loop(Socket, Opts). diff --git a/deps/mochiweb/src/mochiweb_base64url.erl b/deps/mochiweb/src/mochiweb_base64url.erl new file mode 100644 index 0000000..e6a8e13 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_base64url.erl @@ -0,0 +1,105 @@ +%% @author Bob Ippolito +%% @copyright 2013 Mochi Media, Inc. +%% +%% 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. + +-module(mochiweb_base64url). +-export([encode/1, decode/1]). + +%% @doc URL and filename safe base64 variant with no padding, +%% also known as "base64url" per RFC 4648. +%% +%% This differs from base64 in the following ways: +%% '-' is used in place of '+' (62), +%% '_' is used in place of '/' (63), +%% padding is implicit rather than explicit ('='). + +-spec encode(iolist() | binary()) -> binary(). +encode(B) when is_binary(B) -> + encode_binary(B); +encode(L) when is_list(L) -> + encode_binary(iolist_to_binary(L)). + +-spec decode(iolist() | binary()) -> binary(). +decode(B) when is_binary(B) -> + decode_binary(B); +decode(L) when is_list(L) -> + decode_binary(iolist_to_binary(L)). + +%% Implementation, derived from stdlib base64.erl + +%% One-based decode map. +-define(DECODE_MAP, + {bad,bad,bad,bad,bad,bad,bad,bad,ws,ws,bad,bad,ws,bad,bad, %1-15 + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, %16-31 + ws,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,62,bad,bad, %32-47 + 52,53,54,55,56,57,58,59,60,61,bad,bad,bad,bad,bad,bad, %48-63 + bad,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, %64-79 + 15,16,17,18,19,20,21,22,23,24,25,bad,bad,bad,bad,63, %80-95 + bad,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40, %96-111 + 41,42,43,44,45,46,47,48,49,50,51,bad,bad,bad,bad,bad, %112-127 + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad, + bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad,bad}). + +encode_binary(Bin) -> + Split = 3*(byte_size(Bin) div 3), + <> = Bin, + Main = << <<(b64e(C)):8>> || <> <= Main0 >>, + case Rest of + <> -> + <
>; + <> -> + <
>; + <<>> -> + Main + end. + +decode_binary(Bin) -> + Main = << <<(b64d(C)):6>> || <> <= Bin, + (C =/= $\t andalso C =/= $\s andalso + C =/= $\r andalso C =/= $\n) >>, + case bit_size(Main) rem 8 of + 0 -> + Main; + N -> + Split = byte_size(Main) - 1, + <> = Main, + Result + end. + +%% accessors + +b64e(X) -> + element(X+1, + {$A, $B, $C, $D, $E, $F, $G, $H, $I, $J, $K, $L, $M, $N, + $O, $P, $Q, $R, $S, $T, $U, $V, $W, $X, $Y, $Z, + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, + $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, + $0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $-, $_}). + +b64d(X) -> + b64d_ok(element(X, ?DECODE_MAP)). + +b64d_ok(I) when is_integer(I) -> I. diff --git a/deps/mochiweb/src/mochiweb_charref.erl b/deps/mochiweb/src/mochiweb_charref.erl new file mode 100644 index 0000000..143452e --- /dev/null +++ b/deps/mochiweb/src/mochiweb_charref.erl @@ -0,0 +1,2201 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Converts HTML 5 charrefs and entities to codepoints (or lists of code points). +-module(mochiweb_charref). +-export([charref/1]). + +%% External API. + +%% @doc Convert a decimal charref, hex charref, or html entity to a unicode +%% codepoint, or return undefined on failure. +%% The input should not include an ampersand or semicolon. +%% charref("#38") = 38, charref("#x26") = 38, charref("amp") = 38. +-spec charref(binary() | string()) -> integer() | [integer()] | undefined. +charref(B) when is_binary(B) -> + charref(binary_to_list(B)); +charref([$#, C | L]) when C =:= $x orelse C =:= $X -> + try erlang:list_to_integer(L, 16) + catch + error:badarg -> undefined + end; +charref([$# | L]) -> + try list_to_integer(L) + catch + error:badarg -> undefined + end; +charref(L) -> + entity(L). + +%% Internal API. + +%% [2011-10-14] Generated from: +%% http://www.w3.org/TR/html5/named-character-references.html + +entity("AElig") -> 16#000C6; +entity("AMP") -> 16#00026; +entity("Aacute") -> 16#000C1; +entity("Abreve") -> 16#00102; +entity("Acirc") -> 16#000C2; +entity("Acy") -> 16#00410; +entity("Afr") -> 16#1D504; +entity("Agrave") -> 16#000C0; +entity("Alpha") -> 16#00391; +entity("Amacr") -> 16#00100; +entity("And") -> 16#02A53; +entity("Aogon") -> 16#00104; +entity("Aopf") -> 16#1D538; +entity("ApplyFunction") -> 16#02061; +entity("Aring") -> 16#000C5; +entity("Ascr") -> 16#1D49C; +entity("Assign") -> 16#02254; +entity("Atilde") -> 16#000C3; +entity("Auml") -> 16#000C4; +entity("Backslash") -> 16#02216; +entity("Barv") -> 16#02AE7; +entity("Barwed") -> 16#02306; +entity("Bcy") -> 16#00411; +entity("Because") -> 16#02235; +entity("Bernoullis") -> 16#0212C; +entity("Beta") -> 16#00392; +entity("Bfr") -> 16#1D505; +entity("Bopf") -> 16#1D539; +entity("Breve") -> 16#002D8; +entity("Bscr") -> 16#0212C; +entity("Bumpeq") -> 16#0224E; +entity("CHcy") -> 16#00427; +entity("COPY") -> 16#000A9; +entity("Cacute") -> 16#00106; +entity("Cap") -> 16#022D2; +entity("CapitalDifferentialD") -> 16#02145; +entity("Cayleys") -> 16#0212D; +entity("Ccaron") -> 16#0010C; +entity("Ccedil") -> 16#000C7; +entity("Ccirc") -> 16#00108; +entity("Cconint") -> 16#02230; +entity("Cdot") -> 16#0010A; +entity("Cedilla") -> 16#000B8; +entity("CenterDot") -> 16#000B7; +entity("Cfr") -> 16#0212D; +entity("Chi") -> 16#003A7; +entity("CircleDot") -> 16#02299; +entity("CircleMinus") -> 16#02296; +entity("CirclePlus") -> 16#02295; +entity("CircleTimes") -> 16#02297; +entity("ClockwiseContourIntegral") -> 16#02232; +entity("CloseCurlyDoubleQuote") -> 16#0201D; +entity("CloseCurlyQuote") -> 16#02019; +entity("Colon") -> 16#02237; +entity("Colone") -> 16#02A74; +entity("Congruent") -> 16#02261; +entity("Conint") -> 16#0222F; +entity("ContourIntegral") -> 16#0222E; +entity("Copf") -> 16#02102; +entity("Coproduct") -> 16#02210; +entity("CounterClockwiseContourIntegral") -> 16#02233; +entity("Cross") -> 16#02A2F; +entity("Cscr") -> 16#1D49E; +entity("Cup") -> 16#022D3; +entity("CupCap") -> 16#0224D; +entity("DD") -> 16#02145; +entity("DDotrahd") -> 16#02911; +entity("DJcy") -> 16#00402; +entity("DScy") -> 16#00405; +entity("DZcy") -> 16#0040F; +entity("Dagger") -> 16#02021; +entity("Darr") -> 16#021A1; +entity("Dashv") -> 16#02AE4; +entity("Dcaron") -> 16#0010E; +entity("Dcy") -> 16#00414; +entity("Del") -> 16#02207; +entity("Delta") -> 16#00394; +entity("Dfr") -> 16#1D507; +entity("DiacriticalAcute") -> 16#000B4; +entity("DiacriticalDot") -> 16#002D9; +entity("DiacriticalDoubleAcute") -> 16#002DD; +entity("DiacriticalGrave") -> 16#00060; +entity("DiacriticalTilde") -> 16#002DC; +entity("Diamond") -> 16#022C4; +entity("DifferentialD") -> 16#02146; +entity("Dopf") -> 16#1D53B; +entity("Dot") -> 16#000A8; +entity("DotDot") -> 16#020DC; +entity("DotEqual") -> 16#02250; +entity("DoubleContourIntegral") -> 16#0222F; +entity("DoubleDot") -> 16#000A8; +entity("DoubleDownArrow") -> 16#021D3; +entity("DoubleLeftArrow") -> 16#021D0; +entity("DoubleLeftRightArrow") -> 16#021D4; +entity("DoubleLeftTee") -> 16#02AE4; +entity("DoubleLongLeftArrow") -> 16#027F8; +entity("DoubleLongLeftRightArrow") -> 16#027FA; +entity("DoubleLongRightArrow") -> 16#027F9; +entity("DoubleRightArrow") -> 16#021D2; +entity("DoubleRightTee") -> 16#022A8; +entity("DoubleUpArrow") -> 16#021D1; +entity("DoubleUpDownArrow") -> 16#021D5; +entity("DoubleVerticalBar") -> 16#02225; +entity("DownArrow") -> 16#02193; +entity("DownArrowBar") -> 16#02913; +entity("DownArrowUpArrow") -> 16#021F5; +entity("DownBreve") -> 16#00311; +entity("DownLeftRightVector") -> 16#02950; +entity("DownLeftTeeVector") -> 16#0295E; +entity("DownLeftVector") -> 16#021BD; +entity("DownLeftVectorBar") -> 16#02956; +entity("DownRightTeeVector") -> 16#0295F; +entity("DownRightVector") -> 16#021C1; +entity("DownRightVectorBar") -> 16#02957; +entity("DownTee") -> 16#022A4; +entity("DownTeeArrow") -> 16#021A7; +entity("Downarrow") -> 16#021D3; +entity("Dscr") -> 16#1D49F; +entity("Dstrok") -> 16#00110; +entity("ENG") -> 16#0014A; +entity("ETH") -> 16#000D0; +entity("Eacute") -> 16#000C9; +entity("Ecaron") -> 16#0011A; +entity("Ecirc") -> 16#000CA; +entity("Ecy") -> 16#0042D; +entity("Edot") -> 16#00116; +entity("Efr") -> 16#1D508; +entity("Egrave") -> 16#000C8; +entity("Element") -> 16#02208; +entity("Emacr") -> 16#00112; +entity("EmptySmallSquare") -> 16#025FB; +entity("EmptyVerySmallSquare") -> 16#025AB; +entity("Eogon") -> 16#00118; +entity("Eopf") -> 16#1D53C; +entity("Epsilon") -> 16#00395; +entity("Equal") -> 16#02A75; +entity("EqualTilde") -> 16#02242; +entity("Equilibrium") -> 16#021CC; +entity("Escr") -> 16#02130; +entity("Esim") -> 16#02A73; +entity("Eta") -> 16#00397; +entity("Euml") -> 16#000CB; +entity("Exists") -> 16#02203; +entity("ExponentialE") -> 16#02147; +entity("Fcy") -> 16#00424; +entity("Ffr") -> 16#1D509; +entity("FilledSmallSquare") -> 16#025FC; +entity("FilledVerySmallSquare") -> 16#025AA; +entity("Fopf") -> 16#1D53D; +entity("ForAll") -> 16#02200; +entity("Fouriertrf") -> 16#02131; +entity("Fscr") -> 16#02131; +entity("GJcy") -> 16#00403; +entity("GT") -> 16#0003E; +entity("Gamma") -> 16#00393; +entity("Gammad") -> 16#003DC; +entity("Gbreve") -> 16#0011E; +entity("Gcedil") -> 16#00122; +entity("Gcirc") -> 16#0011C; +entity("Gcy") -> 16#00413; +entity("Gdot") -> 16#00120; +entity("Gfr") -> 16#1D50A; +entity("Gg") -> 16#022D9; +entity("Gopf") -> 16#1D53E; +entity("GreaterEqual") -> 16#02265; +entity("GreaterEqualLess") -> 16#022DB; +entity("GreaterFullEqual") -> 16#02267; +entity("GreaterGreater") -> 16#02AA2; +entity("GreaterLess") -> 16#02277; +entity("GreaterSlantEqual") -> 16#02A7E; +entity("GreaterTilde") -> 16#02273; +entity("Gscr") -> 16#1D4A2; +entity("Gt") -> 16#0226B; +entity("HARDcy") -> 16#0042A; +entity("Hacek") -> 16#002C7; +entity("Hat") -> 16#0005E; +entity("Hcirc") -> 16#00124; +entity("Hfr") -> 16#0210C; +entity("HilbertSpace") -> 16#0210B; +entity("Hopf") -> 16#0210D; +entity("HorizontalLine") -> 16#02500; +entity("Hscr") -> 16#0210B; +entity("Hstrok") -> 16#00126; +entity("HumpDownHump") -> 16#0224E; +entity("HumpEqual") -> 16#0224F; +entity("IEcy") -> 16#00415; +entity("IJlig") -> 16#00132; +entity("IOcy") -> 16#00401; +entity("Iacute") -> 16#000CD; +entity("Icirc") -> 16#000CE; +entity("Icy") -> 16#00418; +entity("Idot") -> 16#00130; +entity("Ifr") -> 16#02111; +entity("Igrave") -> 16#000CC; +entity("Im") -> 16#02111; +entity("Imacr") -> 16#0012A; +entity("ImaginaryI") -> 16#02148; +entity("Implies") -> 16#021D2; +entity("Int") -> 16#0222C; +entity("Integral") -> 16#0222B; +entity("Intersection") -> 16#022C2; +entity("InvisibleComma") -> 16#02063; +entity("InvisibleTimes") -> 16#02062; +entity("Iogon") -> 16#0012E; +entity("Iopf") -> 16#1D540; +entity("Iota") -> 16#00399; +entity("Iscr") -> 16#02110; +entity("Itilde") -> 16#00128; +entity("Iukcy") -> 16#00406; +entity("Iuml") -> 16#000CF; +entity("Jcirc") -> 16#00134; +entity("Jcy") -> 16#00419; +entity("Jfr") -> 16#1D50D; +entity("Jopf") -> 16#1D541; +entity("Jscr") -> 16#1D4A5; +entity("Jsercy") -> 16#00408; +entity("Jukcy") -> 16#00404; +entity("KHcy") -> 16#00425; +entity("KJcy") -> 16#0040C; +entity("Kappa") -> 16#0039A; +entity("Kcedil") -> 16#00136; +entity("Kcy") -> 16#0041A; +entity("Kfr") -> 16#1D50E; +entity("Kopf") -> 16#1D542; +entity("Kscr") -> 16#1D4A6; +entity("LJcy") -> 16#00409; +entity("LT") -> 16#0003C; +entity("Lacute") -> 16#00139; +entity("Lambda") -> 16#0039B; +entity("Lang") -> 16#027EA; +entity("Laplacetrf") -> 16#02112; +entity("Larr") -> 16#0219E; +entity("Lcaron") -> 16#0013D; +entity("Lcedil") -> 16#0013B; +entity("Lcy") -> 16#0041B; +entity("LeftAngleBracket") -> 16#027E8; +entity("LeftArrow") -> 16#02190; +entity("LeftArrowBar") -> 16#021E4; +entity("LeftArrowRightArrow") -> 16#021C6; +entity("LeftCeiling") -> 16#02308; +entity("LeftDoubleBracket") -> 16#027E6; +entity("LeftDownTeeVector") -> 16#02961; +entity("LeftDownVector") -> 16#021C3; +entity("LeftDownVectorBar") -> 16#02959; +entity("LeftFloor") -> 16#0230A; +entity("LeftRightArrow") -> 16#02194; +entity("LeftRightVector") -> 16#0294E; +entity("LeftTee") -> 16#022A3; +entity("LeftTeeArrow") -> 16#021A4; +entity("LeftTeeVector") -> 16#0295A; +entity("LeftTriangle") -> 16#022B2; +entity("LeftTriangleBar") -> 16#029CF; +entity("LeftTriangleEqual") -> 16#022B4; +entity("LeftUpDownVector") -> 16#02951; +entity("LeftUpTeeVector") -> 16#02960; +entity("LeftUpVector") -> 16#021BF; +entity("LeftUpVectorBar") -> 16#02958; +entity("LeftVector") -> 16#021BC; +entity("LeftVectorBar") -> 16#02952; +entity("Leftarrow") -> 16#021D0; +entity("Leftrightarrow") -> 16#021D4; +entity("LessEqualGreater") -> 16#022DA; +entity("LessFullEqual") -> 16#02266; +entity("LessGreater") -> 16#02276; +entity("LessLess") -> 16#02AA1; +entity("LessSlantEqual") -> 16#02A7D; +entity("LessTilde") -> 16#02272; +entity("Lfr") -> 16#1D50F; +entity("Ll") -> 16#022D8; +entity("Lleftarrow") -> 16#021DA; +entity("Lmidot") -> 16#0013F; +entity("LongLeftArrow") -> 16#027F5; +entity("LongLeftRightArrow") -> 16#027F7; +entity("LongRightArrow") -> 16#027F6; +entity("Longleftarrow") -> 16#027F8; +entity("Longleftrightarrow") -> 16#027FA; +entity("Longrightarrow") -> 16#027F9; +entity("Lopf") -> 16#1D543; +entity("LowerLeftArrow") -> 16#02199; +entity("LowerRightArrow") -> 16#02198; +entity("Lscr") -> 16#02112; +entity("Lsh") -> 16#021B0; +entity("Lstrok") -> 16#00141; +entity("Lt") -> 16#0226A; +entity("Map") -> 16#02905; +entity("Mcy") -> 16#0041C; +entity("MediumSpace") -> 16#0205F; +entity("Mellintrf") -> 16#02133; +entity("Mfr") -> 16#1D510; +entity("MinusPlus") -> 16#02213; +entity("Mopf") -> 16#1D544; +entity("Mscr") -> 16#02133; +entity("Mu") -> 16#0039C; +entity("NJcy") -> 16#0040A; +entity("Nacute") -> 16#00143; +entity("Ncaron") -> 16#00147; +entity("Ncedil") -> 16#00145; +entity("Ncy") -> 16#0041D; +entity("NegativeMediumSpace") -> 16#0200B; +entity("NegativeThickSpace") -> 16#0200B; +entity("NegativeThinSpace") -> 16#0200B; +entity("NegativeVeryThinSpace") -> 16#0200B; +entity("NestedGreaterGreater") -> 16#0226B; +entity("NestedLessLess") -> 16#0226A; +entity("NewLine") -> 16#0000A; +entity("Nfr") -> 16#1D511; +entity("NoBreak") -> 16#02060; +entity("NonBreakingSpace") -> 16#000A0; +entity("Nopf") -> 16#02115; +entity("Not") -> 16#02AEC; +entity("NotCongruent") -> 16#02262; +entity("NotCupCap") -> 16#0226D; +entity("NotDoubleVerticalBar") -> 16#02226; +entity("NotElement") -> 16#02209; +entity("NotEqual") -> 16#02260; +entity("NotEqualTilde") -> [16#02242, 16#00338]; +entity("NotExists") -> 16#02204; +entity("NotGreater") -> 16#0226F; +entity("NotGreaterEqual") -> 16#02271; +entity("NotGreaterFullEqual") -> [16#02267, 16#00338]; +entity("NotGreaterGreater") -> [16#0226B, 16#00338]; +entity("NotGreaterLess") -> 16#02279; +entity("NotGreaterSlantEqual") -> [16#02A7E, 16#00338]; +entity("NotGreaterTilde") -> 16#02275; +entity("NotHumpDownHump") -> [16#0224E, 16#00338]; +entity("NotHumpEqual") -> [16#0224F, 16#00338]; +entity("NotLeftTriangle") -> 16#022EA; +entity("NotLeftTriangleBar") -> [16#029CF, 16#00338]; +entity("NotLeftTriangleEqual") -> 16#022EC; +entity("NotLess") -> 16#0226E; +entity("NotLessEqual") -> 16#02270; +entity("NotLessGreater") -> 16#02278; +entity("NotLessLess") -> [16#0226A, 16#00338]; +entity("NotLessSlantEqual") -> [16#02A7D, 16#00338]; +entity("NotLessTilde") -> 16#02274; +entity("NotNestedGreaterGreater") -> [16#02AA2, 16#00338]; +entity("NotNestedLessLess") -> [16#02AA1, 16#00338]; +entity("NotPrecedes") -> 16#02280; +entity("NotPrecedesEqual") -> [16#02AAF, 16#00338]; +entity("NotPrecedesSlantEqual") -> 16#022E0; +entity("NotReverseElement") -> 16#0220C; +entity("NotRightTriangle") -> 16#022EB; +entity("NotRightTriangleBar") -> [16#029D0, 16#00338]; +entity("NotRightTriangleEqual") -> 16#022ED; +entity("NotSquareSubset") -> [16#0228F, 16#00338]; +entity("NotSquareSubsetEqual") -> 16#022E2; +entity("NotSquareSuperset") -> [16#02290, 16#00338]; +entity("NotSquareSupersetEqual") -> 16#022E3; +entity("NotSubset") -> [16#02282, 16#020D2]; +entity("NotSubsetEqual") -> 16#02288; +entity("NotSucceeds") -> 16#02281; +entity("NotSucceedsEqual") -> [16#02AB0, 16#00338]; +entity("NotSucceedsSlantEqual") -> 16#022E1; +entity("NotSucceedsTilde") -> [16#0227F, 16#00338]; +entity("NotSuperset") -> [16#02283, 16#020D2]; +entity("NotSupersetEqual") -> 16#02289; +entity("NotTilde") -> 16#02241; +entity("NotTildeEqual") -> 16#02244; +entity("NotTildeFullEqual") -> 16#02247; +entity("NotTildeTilde") -> 16#02249; +entity("NotVerticalBar") -> 16#02224; +entity("Nscr") -> 16#1D4A9; +entity("Ntilde") -> 16#000D1; +entity("Nu") -> 16#0039D; +entity("OElig") -> 16#00152; +entity("Oacute") -> 16#000D3; +entity("Ocirc") -> 16#000D4; +entity("Ocy") -> 16#0041E; +entity("Odblac") -> 16#00150; +entity("Ofr") -> 16#1D512; +entity("Ograve") -> 16#000D2; +entity("Omacr") -> 16#0014C; +entity("Omega") -> 16#003A9; +entity("Omicron") -> 16#0039F; +entity("Oopf") -> 16#1D546; +entity("OpenCurlyDoubleQuote") -> 16#0201C; +entity("OpenCurlyQuote") -> 16#02018; +entity("Or") -> 16#02A54; +entity("Oscr") -> 16#1D4AA; +entity("Oslash") -> 16#000D8; +entity("Otilde") -> 16#000D5; +entity("Otimes") -> 16#02A37; +entity("Ouml") -> 16#000D6; +entity("OverBar") -> 16#0203E; +entity("OverBrace") -> 16#023DE; +entity("OverBracket") -> 16#023B4; +entity("OverParenthesis") -> 16#023DC; +entity("PartialD") -> 16#02202; +entity("Pcy") -> 16#0041F; +entity("Pfr") -> 16#1D513; +entity("Phi") -> 16#003A6; +entity("Pi") -> 16#003A0; +entity("PlusMinus") -> 16#000B1; +entity("Poincareplane") -> 16#0210C; +entity("Popf") -> 16#02119; +entity("Pr") -> 16#02ABB; +entity("Precedes") -> 16#0227A; +entity("PrecedesEqual") -> 16#02AAF; +entity("PrecedesSlantEqual") -> 16#0227C; +entity("PrecedesTilde") -> 16#0227E; +entity("Prime") -> 16#02033; +entity("Product") -> 16#0220F; +entity("Proportion") -> 16#02237; +entity("Proportional") -> 16#0221D; +entity("Pscr") -> 16#1D4AB; +entity("Psi") -> 16#003A8; +entity("QUOT") -> 16#00022; +entity("Qfr") -> 16#1D514; +entity("Qopf") -> 16#0211A; +entity("Qscr") -> 16#1D4AC; +entity("RBarr") -> 16#02910; +entity("REG") -> 16#000AE; +entity("Racute") -> 16#00154; +entity("Rang") -> 16#027EB; +entity("Rarr") -> 16#021A0; +entity("Rarrtl") -> 16#02916; +entity("Rcaron") -> 16#00158; +entity("Rcedil") -> 16#00156; +entity("Rcy") -> 16#00420; +entity("Re") -> 16#0211C; +entity("ReverseElement") -> 16#0220B; +entity("ReverseEquilibrium") -> 16#021CB; +entity("ReverseUpEquilibrium") -> 16#0296F; +entity("Rfr") -> 16#0211C; +entity("Rho") -> 16#003A1; +entity("RightAngleBracket") -> 16#027E9; +entity("RightArrow") -> 16#02192; +entity("RightArrowBar") -> 16#021E5; +entity("RightArrowLeftArrow") -> 16#021C4; +entity("RightCeiling") -> 16#02309; +entity("RightDoubleBracket") -> 16#027E7; +entity("RightDownTeeVector") -> 16#0295D; +entity("RightDownVector") -> 16#021C2; +entity("RightDownVectorBar") -> 16#02955; +entity("RightFloor") -> 16#0230B; +entity("RightTee") -> 16#022A2; +entity("RightTeeArrow") -> 16#021A6; +entity("RightTeeVector") -> 16#0295B; +entity("RightTriangle") -> 16#022B3; +entity("RightTriangleBar") -> 16#029D0; +entity("RightTriangleEqual") -> 16#022B5; +entity("RightUpDownVector") -> 16#0294F; +entity("RightUpTeeVector") -> 16#0295C; +entity("RightUpVector") -> 16#021BE; +entity("RightUpVectorBar") -> 16#02954; +entity("RightVector") -> 16#021C0; +entity("RightVectorBar") -> 16#02953; +entity("Rightarrow") -> 16#021D2; +entity("Ropf") -> 16#0211D; +entity("RoundImplies") -> 16#02970; +entity("Rrightarrow") -> 16#021DB; +entity("Rscr") -> 16#0211B; +entity("Rsh") -> 16#021B1; +entity("RuleDelayed") -> 16#029F4; +entity("SHCHcy") -> 16#00429; +entity("SHcy") -> 16#00428; +entity("SOFTcy") -> 16#0042C; +entity("Sacute") -> 16#0015A; +entity("Sc") -> 16#02ABC; +entity("Scaron") -> 16#00160; +entity("Scedil") -> 16#0015E; +entity("Scirc") -> 16#0015C; +entity("Scy") -> 16#00421; +entity("Sfr") -> 16#1D516; +entity("ShortDownArrow") -> 16#02193; +entity("ShortLeftArrow") -> 16#02190; +entity("ShortRightArrow") -> 16#02192; +entity("ShortUpArrow") -> 16#02191; +entity("Sigma") -> 16#003A3; +entity("SmallCircle") -> 16#02218; +entity("Sopf") -> 16#1D54A; +entity("Sqrt") -> 16#0221A; +entity("Square") -> 16#025A1; +entity("SquareIntersection") -> 16#02293; +entity("SquareSubset") -> 16#0228F; +entity("SquareSubsetEqual") -> 16#02291; +entity("SquareSuperset") -> 16#02290; +entity("SquareSupersetEqual") -> 16#02292; +entity("SquareUnion") -> 16#02294; +entity("Sscr") -> 16#1D4AE; +entity("Star") -> 16#022C6; +entity("Sub") -> 16#022D0; +entity("Subset") -> 16#022D0; +entity("SubsetEqual") -> 16#02286; +entity("Succeeds") -> 16#0227B; +entity("SucceedsEqual") -> 16#02AB0; +entity("SucceedsSlantEqual") -> 16#0227D; +entity("SucceedsTilde") -> 16#0227F; +entity("SuchThat") -> 16#0220B; +entity("Sum") -> 16#02211; +entity("Sup") -> 16#022D1; +entity("Superset") -> 16#02283; +entity("SupersetEqual") -> 16#02287; +entity("Supset") -> 16#022D1; +entity("THORN") -> 16#000DE; +entity("TRADE") -> 16#02122; +entity("TSHcy") -> 16#0040B; +entity("TScy") -> 16#00426; +entity("Tab") -> 16#00009; +entity("Tau") -> 16#003A4; +entity("Tcaron") -> 16#00164; +entity("Tcedil") -> 16#00162; +entity("Tcy") -> 16#00422; +entity("Tfr") -> 16#1D517; +entity("Therefore") -> 16#02234; +entity("Theta") -> 16#00398; +entity("ThickSpace") -> [16#0205F, 16#0200A]; +entity("ThinSpace") -> 16#02009; +entity("Tilde") -> 16#0223C; +entity("TildeEqual") -> 16#02243; +entity("TildeFullEqual") -> 16#02245; +entity("TildeTilde") -> 16#02248; +entity("Topf") -> 16#1D54B; +entity("TripleDot") -> 16#020DB; +entity("Tscr") -> 16#1D4AF; +entity("Tstrok") -> 16#00166; +entity("Uacute") -> 16#000DA; +entity("Uarr") -> 16#0219F; +entity("Uarrocir") -> 16#02949; +entity("Ubrcy") -> 16#0040E; +entity("Ubreve") -> 16#0016C; +entity("Ucirc") -> 16#000DB; +entity("Ucy") -> 16#00423; +entity("Udblac") -> 16#00170; +entity("Ufr") -> 16#1D518; +entity("Ugrave") -> 16#000D9; +entity("Umacr") -> 16#0016A; +entity("UnderBar") -> 16#0005F; +entity("UnderBrace") -> 16#023DF; +entity("UnderBracket") -> 16#023B5; +entity("UnderParenthesis") -> 16#023DD; +entity("Union") -> 16#022C3; +entity("UnionPlus") -> 16#0228E; +entity("Uogon") -> 16#00172; +entity("Uopf") -> 16#1D54C; +entity("UpArrow") -> 16#02191; +entity("UpArrowBar") -> 16#02912; +entity("UpArrowDownArrow") -> 16#021C5; +entity("UpDownArrow") -> 16#02195; +entity("UpEquilibrium") -> 16#0296E; +entity("UpTee") -> 16#022A5; +entity("UpTeeArrow") -> 16#021A5; +entity("Uparrow") -> 16#021D1; +entity("Updownarrow") -> 16#021D5; +entity("UpperLeftArrow") -> 16#02196; +entity("UpperRightArrow") -> 16#02197; +entity("Upsi") -> 16#003D2; +entity("Upsilon") -> 16#003A5; +entity("Uring") -> 16#0016E; +entity("Uscr") -> 16#1D4B0; +entity("Utilde") -> 16#00168; +entity("Uuml") -> 16#000DC; +entity("VDash") -> 16#022AB; +entity("Vbar") -> 16#02AEB; +entity("Vcy") -> 16#00412; +entity("Vdash") -> 16#022A9; +entity("Vdashl") -> 16#02AE6; +entity("Vee") -> 16#022C1; +entity("Verbar") -> 16#02016; +entity("Vert") -> 16#02016; +entity("VerticalBar") -> 16#02223; +entity("VerticalLine") -> 16#0007C; +entity("VerticalSeparator") -> 16#02758; +entity("VerticalTilde") -> 16#02240; +entity("VeryThinSpace") -> 16#0200A; +entity("Vfr") -> 16#1D519; +entity("Vopf") -> 16#1D54D; +entity("Vscr") -> 16#1D4B1; +entity("Vvdash") -> 16#022AA; +entity("Wcirc") -> 16#00174; +entity("Wedge") -> 16#022C0; +entity("Wfr") -> 16#1D51A; +entity("Wopf") -> 16#1D54E; +entity("Wscr") -> 16#1D4B2; +entity("Xfr") -> 16#1D51B; +entity("Xi") -> 16#0039E; +entity("Xopf") -> 16#1D54F; +entity("Xscr") -> 16#1D4B3; +entity("YAcy") -> 16#0042F; +entity("YIcy") -> 16#00407; +entity("YUcy") -> 16#0042E; +entity("Yacute") -> 16#000DD; +entity("Ycirc") -> 16#00176; +entity("Ycy") -> 16#0042B; +entity("Yfr") -> 16#1D51C; +entity("Yopf") -> 16#1D550; +entity("Yscr") -> 16#1D4B4; +entity("Yuml") -> 16#00178; +entity("ZHcy") -> 16#00416; +entity("Zacute") -> 16#00179; +entity("Zcaron") -> 16#0017D; +entity("Zcy") -> 16#00417; +entity("Zdot") -> 16#0017B; +entity("ZeroWidthSpace") -> 16#0200B; +entity("Zeta") -> 16#00396; +entity("Zfr") -> 16#02128; +entity("Zopf") -> 16#02124; +entity("Zscr") -> 16#1D4B5; +entity("aacute") -> 16#000E1; +entity("abreve") -> 16#00103; +entity("ac") -> 16#0223E; +entity("acE") -> [16#0223E, 16#00333]; +entity("acd") -> 16#0223F; +entity("acirc") -> 16#000E2; +entity("acute") -> 16#000B4; +entity("acy") -> 16#00430; +entity("aelig") -> 16#000E6; +entity("af") -> 16#02061; +entity("afr") -> 16#1D51E; +entity("agrave") -> 16#000E0; +entity("alefsym") -> 16#02135; +entity("aleph") -> 16#02135; +entity("alpha") -> 16#003B1; +entity("amacr") -> 16#00101; +entity("amalg") -> 16#02A3F; +entity("amp") -> 16#00026; +entity("and") -> 16#02227; +entity("andand") -> 16#02A55; +entity("andd") -> 16#02A5C; +entity("andslope") -> 16#02A58; +entity("andv") -> 16#02A5A; +entity("ang") -> 16#02220; +entity("ange") -> 16#029A4; +entity("angle") -> 16#02220; +entity("angmsd") -> 16#02221; +entity("angmsdaa") -> 16#029A8; +entity("angmsdab") -> 16#029A9; +entity("angmsdac") -> 16#029AA; +entity("angmsdad") -> 16#029AB; +entity("angmsdae") -> 16#029AC; +entity("angmsdaf") -> 16#029AD; +entity("angmsdag") -> 16#029AE; +entity("angmsdah") -> 16#029AF; +entity("angrt") -> 16#0221F; +entity("angrtvb") -> 16#022BE; +entity("angrtvbd") -> 16#0299D; +entity("angsph") -> 16#02222; +entity("angst") -> 16#000C5; +entity("angzarr") -> 16#0237C; +entity("aogon") -> 16#00105; +entity("aopf") -> 16#1D552; +entity("ap") -> 16#02248; +entity("apE") -> 16#02A70; +entity("apacir") -> 16#02A6F; +entity("ape") -> 16#0224A; +entity("apid") -> 16#0224B; +entity("apos") -> 16#00027; +entity("approx") -> 16#02248; +entity("approxeq") -> 16#0224A; +entity("aring") -> 16#000E5; +entity("ascr") -> 16#1D4B6; +entity("ast") -> 16#0002A; +entity("asymp") -> 16#02248; +entity("asympeq") -> 16#0224D; +entity("atilde") -> 16#000E3; +entity("auml") -> 16#000E4; +entity("awconint") -> 16#02233; +entity("awint") -> 16#02A11; +entity("bNot") -> 16#02AED; +entity("backcong") -> 16#0224C; +entity("backepsilon") -> 16#003F6; +entity("backprime") -> 16#02035; +entity("backsim") -> 16#0223D; +entity("backsimeq") -> 16#022CD; +entity("barvee") -> 16#022BD; +entity("barwed") -> 16#02305; +entity("barwedge") -> 16#02305; +entity("bbrk") -> 16#023B5; +entity("bbrktbrk") -> 16#023B6; +entity("bcong") -> 16#0224C; +entity("bcy") -> 16#00431; +entity("bdquo") -> 16#0201E; +entity("becaus") -> 16#02235; +entity("because") -> 16#02235; +entity("bemptyv") -> 16#029B0; +entity("bepsi") -> 16#003F6; +entity("bernou") -> 16#0212C; +entity("beta") -> 16#003B2; +entity("beth") -> 16#02136; +entity("between") -> 16#0226C; +entity("bfr") -> 16#1D51F; +entity("bigcap") -> 16#022C2; +entity("bigcirc") -> 16#025EF; +entity("bigcup") -> 16#022C3; +entity("bigodot") -> 16#02A00; +entity("bigoplus") -> 16#02A01; +entity("bigotimes") -> 16#02A02; +entity("bigsqcup") -> 16#02A06; +entity("bigstar") -> 16#02605; +entity("bigtriangledown") -> 16#025BD; +entity("bigtriangleup") -> 16#025B3; +entity("biguplus") -> 16#02A04; +entity("bigvee") -> 16#022C1; +entity("bigwedge") -> 16#022C0; +entity("bkarow") -> 16#0290D; +entity("blacklozenge") -> 16#029EB; +entity("blacksquare") -> 16#025AA; +entity("blacktriangle") -> 16#025B4; +entity("blacktriangledown") -> 16#025BE; +entity("blacktriangleleft") -> 16#025C2; +entity("blacktriangleright") -> 16#025B8; +entity("blank") -> 16#02423; +entity("blk12") -> 16#02592; +entity("blk14") -> 16#02591; +entity("blk34") -> 16#02593; +entity("block") -> 16#02588; +entity("bne") -> [16#0003D, 16#020E5]; +entity("bnequiv") -> [16#02261, 16#020E5]; +entity("bnot") -> 16#02310; +entity("bopf") -> 16#1D553; +entity("bot") -> 16#022A5; +entity("bottom") -> 16#022A5; +entity("bowtie") -> 16#022C8; +entity("boxDL") -> 16#02557; +entity("boxDR") -> 16#02554; +entity("boxDl") -> 16#02556; +entity("boxDr") -> 16#02553; +entity("boxH") -> 16#02550; +entity("boxHD") -> 16#02566; +entity("boxHU") -> 16#02569; +entity("boxHd") -> 16#02564; +entity("boxHu") -> 16#02567; +entity("boxUL") -> 16#0255D; +entity("boxUR") -> 16#0255A; +entity("boxUl") -> 16#0255C; +entity("boxUr") -> 16#02559; +entity("boxV") -> 16#02551; +entity("boxVH") -> 16#0256C; +entity("boxVL") -> 16#02563; +entity("boxVR") -> 16#02560; +entity("boxVh") -> 16#0256B; +entity("boxVl") -> 16#02562; +entity("boxVr") -> 16#0255F; +entity("boxbox") -> 16#029C9; +entity("boxdL") -> 16#02555; +entity("boxdR") -> 16#02552; +entity("boxdl") -> 16#02510; +entity("boxdr") -> 16#0250C; +entity("boxh") -> 16#02500; +entity("boxhD") -> 16#02565; +entity("boxhU") -> 16#02568; +entity("boxhd") -> 16#0252C; +entity("boxhu") -> 16#02534; +entity("boxminus") -> 16#0229F; +entity("boxplus") -> 16#0229E; +entity("boxtimes") -> 16#022A0; +entity("boxuL") -> 16#0255B; +entity("boxuR") -> 16#02558; +entity("boxul") -> 16#02518; +entity("boxur") -> 16#02514; +entity("boxv") -> 16#02502; +entity("boxvH") -> 16#0256A; +entity("boxvL") -> 16#02561; +entity("boxvR") -> 16#0255E; +entity("boxvh") -> 16#0253C; +entity("boxvl") -> 16#02524; +entity("boxvr") -> 16#0251C; +entity("bprime") -> 16#02035; +entity("breve") -> 16#002D8; +entity("brvbar") -> 16#000A6; +entity("bscr") -> 16#1D4B7; +entity("bsemi") -> 16#0204F; +entity("bsim") -> 16#0223D; +entity("bsime") -> 16#022CD; +entity("bsol") -> 16#0005C; +entity("bsolb") -> 16#029C5; +entity("bsolhsub") -> 16#027C8; +entity("bull") -> 16#02022; +entity("bullet") -> 16#02022; +entity("bump") -> 16#0224E; +entity("bumpE") -> 16#02AAE; +entity("bumpe") -> 16#0224F; +entity("bumpeq") -> 16#0224F; +entity("cacute") -> 16#00107; +entity("cap") -> 16#02229; +entity("capand") -> 16#02A44; +entity("capbrcup") -> 16#02A49; +entity("capcap") -> 16#02A4B; +entity("capcup") -> 16#02A47; +entity("capdot") -> 16#02A40; +entity("caps") -> [16#02229, 16#0FE00]; +entity("caret") -> 16#02041; +entity("caron") -> 16#002C7; +entity("ccaps") -> 16#02A4D; +entity("ccaron") -> 16#0010D; +entity("ccedil") -> 16#000E7; +entity("ccirc") -> 16#00109; +entity("ccups") -> 16#02A4C; +entity("ccupssm") -> 16#02A50; +entity("cdot") -> 16#0010B; +entity("cedil") -> 16#000B8; +entity("cemptyv") -> 16#029B2; +entity("cent") -> 16#000A2; +entity("centerdot") -> 16#000B7; +entity("cfr") -> 16#1D520; +entity("chcy") -> 16#00447; +entity("check") -> 16#02713; +entity("checkmark") -> 16#02713; +entity("chi") -> 16#003C7; +entity("cir") -> 16#025CB; +entity("cirE") -> 16#029C3; +entity("circ") -> 16#002C6; +entity("circeq") -> 16#02257; +entity("circlearrowleft") -> 16#021BA; +entity("circlearrowright") -> 16#021BB; +entity("circledR") -> 16#000AE; +entity("circledS") -> 16#024C8; +entity("circledast") -> 16#0229B; +entity("circledcirc") -> 16#0229A; +entity("circleddash") -> 16#0229D; +entity("cire") -> 16#02257; +entity("cirfnint") -> 16#02A10; +entity("cirmid") -> 16#02AEF; +entity("cirscir") -> 16#029C2; +entity("clubs") -> 16#02663; +entity("clubsuit") -> 16#02663; +entity("colon") -> 16#0003A; +entity("colone") -> 16#02254; +entity("coloneq") -> 16#02254; +entity("comma") -> 16#0002C; +entity("commat") -> 16#00040; +entity("comp") -> 16#02201; +entity("compfn") -> 16#02218; +entity("complement") -> 16#02201; +entity("complexes") -> 16#02102; +entity("cong") -> 16#02245; +entity("congdot") -> 16#02A6D; +entity("conint") -> 16#0222E; +entity("copf") -> 16#1D554; +entity("coprod") -> 16#02210; +entity("copy") -> 16#000A9; +entity("copysr") -> 16#02117; +entity("crarr") -> 16#021B5; +entity("cross") -> 16#02717; +entity("cscr") -> 16#1D4B8; +entity("csub") -> 16#02ACF; +entity("csube") -> 16#02AD1; +entity("csup") -> 16#02AD0; +entity("csupe") -> 16#02AD2; +entity("ctdot") -> 16#022EF; +entity("cudarrl") -> 16#02938; +entity("cudarrr") -> 16#02935; +entity("cuepr") -> 16#022DE; +entity("cuesc") -> 16#022DF; +entity("cularr") -> 16#021B6; +entity("cularrp") -> 16#0293D; +entity("cup") -> 16#0222A; +entity("cupbrcap") -> 16#02A48; +entity("cupcap") -> 16#02A46; +entity("cupcup") -> 16#02A4A; +entity("cupdot") -> 16#0228D; +entity("cupor") -> 16#02A45; +entity("cups") -> [16#0222A, 16#0FE00]; +entity("curarr") -> 16#021B7; +entity("curarrm") -> 16#0293C; +entity("curlyeqprec") -> 16#022DE; +entity("curlyeqsucc") -> 16#022DF; +entity("curlyvee") -> 16#022CE; +entity("curlywedge") -> 16#022CF; +entity("curren") -> 16#000A4; +entity("curvearrowleft") -> 16#021B6; +entity("curvearrowright") -> 16#021B7; +entity("cuvee") -> 16#022CE; +entity("cuwed") -> 16#022CF; +entity("cwconint") -> 16#02232; +entity("cwint") -> 16#02231; +entity("cylcty") -> 16#0232D; +entity("dArr") -> 16#021D3; +entity("dHar") -> 16#02965; +entity("dagger") -> 16#02020; +entity("daleth") -> 16#02138; +entity("darr") -> 16#02193; +entity("dash") -> 16#02010; +entity("dashv") -> 16#022A3; +entity("dbkarow") -> 16#0290F; +entity("dblac") -> 16#002DD; +entity("dcaron") -> 16#0010F; +entity("dcy") -> 16#00434; +entity("dd") -> 16#02146; +entity("ddagger") -> 16#02021; +entity("ddarr") -> 16#021CA; +entity("ddotseq") -> 16#02A77; +entity("deg") -> 16#000B0; +entity("delta") -> 16#003B4; +entity("demptyv") -> 16#029B1; +entity("dfisht") -> 16#0297F; +entity("dfr") -> 16#1D521; +entity("dharl") -> 16#021C3; +entity("dharr") -> 16#021C2; +entity("diam") -> 16#022C4; +entity("diamond") -> 16#022C4; +entity("diamondsuit") -> 16#02666; +entity("diams") -> 16#02666; +entity("die") -> 16#000A8; +entity("digamma") -> 16#003DD; +entity("disin") -> 16#022F2; +entity("div") -> 16#000F7; +entity("divide") -> 16#000F7; +entity("divideontimes") -> 16#022C7; +entity("divonx") -> 16#022C7; +entity("djcy") -> 16#00452; +entity("dlcorn") -> 16#0231E; +entity("dlcrop") -> 16#0230D; +entity("dollar") -> 16#00024; +entity("dopf") -> 16#1D555; +entity("dot") -> 16#002D9; +entity("doteq") -> 16#02250; +entity("doteqdot") -> 16#02251; +entity("dotminus") -> 16#02238; +entity("dotplus") -> 16#02214; +entity("dotsquare") -> 16#022A1; +entity("doublebarwedge") -> 16#02306; +entity("downarrow") -> 16#02193; +entity("downdownarrows") -> 16#021CA; +entity("downharpoonleft") -> 16#021C3; +entity("downharpoonright") -> 16#021C2; +entity("drbkarow") -> 16#02910; +entity("drcorn") -> 16#0231F; +entity("drcrop") -> 16#0230C; +entity("dscr") -> 16#1D4B9; +entity("dscy") -> 16#00455; +entity("dsol") -> 16#029F6; +entity("dstrok") -> 16#00111; +entity("dtdot") -> 16#022F1; +entity("dtri") -> 16#025BF; +entity("dtrif") -> 16#025BE; +entity("duarr") -> 16#021F5; +entity("duhar") -> 16#0296F; +entity("dwangle") -> 16#029A6; +entity("dzcy") -> 16#0045F; +entity("dzigrarr") -> 16#027FF; +entity("eDDot") -> 16#02A77; +entity("eDot") -> 16#02251; +entity("eacute") -> 16#000E9; +entity("easter") -> 16#02A6E; +entity("ecaron") -> 16#0011B; +entity("ecir") -> 16#02256; +entity("ecirc") -> 16#000EA; +entity("ecolon") -> 16#02255; +entity("ecy") -> 16#0044D; +entity("edot") -> 16#00117; +entity("ee") -> 16#02147; +entity("efDot") -> 16#02252; +entity("efr") -> 16#1D522; +entity("eg") -> 16#02A9A; +entity("egrave") -> 16#000E8; +entity("egs") -> 16#02A96; +entity("egsdot") -> 16#02A98; +entity("el") -> 16#02A99; +entity("elinters") -> 16#023E7; +entity("ell") -> 16#02113; +entity("els") -> 16#02A95; +entity("elsdot") -> 16#02A97; +entity("emacr") -> 16#00113; +entity("empty") -> 16#02205; +entity("emptyset") -> 16#02205; +entity("emptyv") -> 16#02205; +entity("emsp") -> 16#02003; +entity("emsp13") -> 16#02004; +entity("emsp14") -> 16#02005; +entity("eng") -> 16#0014B; +entity("ensp") -> 16#02002; +entity("eogon") -> 16#00119; +entity("eopf") -> 16#1D556; +entity("epar") -> 16#022D5; +entity("eparsl") -> 16#029E3; +entity("eplus") -> 16#02A71; +entity("epsi") -> 16#003B5; +entity("epsilon") -> 16#003B5; +entity("epsiv") -> 16#003F5; +entity("eqcirc") -> 16#02256; +entity("eqcolon") -> 16#02255; +entity("eqsim") -> 16#02242; +entity("eqslantgtr") -> 16#02A96; +entity("eqslantless") -> 16#02A95; +entity("equals") -> 16#0003D; +entity("equest") -> 16#0225F; +entity("equiv") -> 16#02261; +entity("equivDD") -> 16#02A78; +entity("eqvparsl") -> 16#029E5; +entity("erDot") -> 16#02253; +entity("erarr") -> 16#02971; +entity("escr") -> 16#0212F; +entity("esdot") -> 16#02250; +entity("esim") -> 16#02242; +entity("eta") -> 16#003B7; +entity("eth") -> 16#000F0; +entity("euml") -> 16#000EB; +entity("euro") -> 16#020AC; +entity("excl") -> 16#00021; +entity("exist") -> 16#02203; +entity("expectation") -> 16#02130; +entity("exponentiale") -> 16#02147; +entity("fallingdotseq") -> 16#02252; +entity("fcy") -> 16#00444; +entity("female") -> 16#02640; +entity("ffilig") -> 16#0FB03; +entity("fflig") -> 16#0FB00; +entity("ffllig") -> 16#0FB04; +entity("ffr") -> 16#1D523; +entity("filig") -> 16#0FB01; +entity("fjlig") -> [16#00066, 16#0006A]; +entity("flat") -> 16#0266D; +entity("fllig") -> 16#0FB02; +entity("fltns") -> 16#025B1; +entity("fnof") -> 16#00192; +entity("fopf") -> 16#1D557; +entity("forall") -> 16#02200; +entity("fork") -> 16#022D4; +entity("forkv") -> 16#02AD9; +entity("fpartint") -> 16#02A0D; +entity("frac12") -> 16#000BD; +entity("frac13") -> 16#02153; +entity("frac14") -> 16#000BC; +entity("frac15") -> 16#02155; +entity("frac16") -> 16#02159; +entity("frac18") -> 16#0215B; +entity("frac23") -> 16#02154; +entity("frac25") -> 16#02156; +entity("frac34") -> 16#000BE; +entity("frac35") -> 16#02157; +entity("frac38") -> 16#0215C; +entity("frac45") -> 16#02158; +entity("frac56") -> 16#0215A; +entity("frac58") -> 16#0215D; +entity("frac78") -> 16#0215E; +entity("frasl") -> 16#02044; +entity("frown") -> 16#02322; +entity("fscr") -> 16#1D4BB; +entity("gE") -> 16#02267; +entity("gEl") -> 16#02A8C; +entity("gacute") -> 16#001F5; +entity("gamma") -> 16#003B3; +entity("gammad") -> 16#003DD; +entity("gap") -> 16#02A86; +entity("gbreve") -> 16#0011F; +entity("gcirc") -> 16#0011D; +entity("gcy") -> 16#00433; +entity("gdot") -> 16#00121; +entity("ge") -> 16#02265; +entity("gel") -> 16#022DB; +entity("geq") -> 16#02265; +entity("geqq") -> 16#02267; +entity("geqslant") -> 16#02A7E; +entity("ges") -> 16#02A7E; +entity("gescc") -> 16#02AA9; +entity("gesdot") -> 16#02A80; +entity("gesdoto") -> 16#02A82; +entity("gesdotol") -> 16#02A84; +entity("gesl") -> [16#022DB, 16#0FE00]; +entity("gesles") -> 16#02A94; +entity("gfr") -> 16#1D524; +entity("gg") -> 16#0226B; +entity("ggg") -> 16#022D9; +entity("gimel") -> 16#02137; +entity("gjcy") -> 16#00453; +entity("gl") -> 16#02277; +entity("glE") -> 16#02A92; +entity("gla") -> 16#02AA5; +entity("glj") -> 16#02AA4; +entity("gnE") -> 16#02269; +entity("gnap") -> 16#02A8A; +entity("gnapprox") -> 16#02A8A; +entity("gne") -> 16#02A88; +entity("gneq") -> 16#02A88; +entity("gneqq") -> 16#02269; +entity("gnsim") -> 16#022E7; +entity("gopf") -> 16#1D558; +entity("grave") -> 16#00060; +entity("gscr") -> 16#0210A; +entity("gsim") -> 16#02273; +entity("gsime") -> 16#02A8E; +entity("gsiml") -> 16#02A90; +entity("gt") -> 16#0003E; +entity("gtcc") -> 16#02AA7; +entity("gtcir") -> 16#02A7A; +entity("gtdot") -> 16#022D7; +entity("gtlPar") -> 16#02995; +entity("gtquest") -> 16#02A7C; +entity("gtrapprox") -> 16#02A86; +entity("gtrarr") -> 16#02978; +entity("gtrdot") -> 16#022D7; +entity("gtreqless") -> 16#022DB; +entity("gtreqqless") -> 16#02A8C; +entity("gtrless") -> 16#02277; +entity("gtrsim") -> 16#02273; +entity("gvertneqq") -> [16#02269, 16#0FE00]; +entity("gvnE") -> [16#02269, 16#0FE00]; +entity("hArr") -> 16#021D4; +entity("hairsp") -> 16#0200A; +entity("half") -> 16#000BD; +entity("hamilt") -> 16#0210B; +entity("hardcy") -> 16#0044A; +entity("harr") -> 16#02194; +entity("harrcir") -> 16#02948; +entity("harrw") -> 16#021AD; +entity("hbar") -> 16#0210F; +entity("hcirc") -> 16#00125; +entity("hearts") -> 16#02665; +entity("heartsuit") -> 16#02665; +entity("hellip") -> 16#02026; +entity("hercon") -> 16#022B9; +entity("hfr") -> 16#1D525; +entity("hksearow") -> 16#02925; +entity("hkswarow") -> 16#02926; +entity("hoarr") -> 16#021FF; +entity("homtht") -> 16#0223B; +entity("hookleftarrow") -> 16#021A9; +entity("hookrightarrow") -> 16#021AA; +entity("hopf") -> 16#1D559; +entity("horbar") -> 16#02015; +entity("hscr") -> 16#1D4BD; +entity("hslash") -> 16#0210F; +entity("hstrok") -> 16#00127; +entity("hybull") -> 16#02043; +entity("hyphen") -> 16#02010; +entity("iacute") -> 16#000ED; +entity("ic") -> 16#02063; +entity("icirc") -> 16#000EE; +entity("icy") -> 16#00438; +entity("iecy") -> 16#00435; +entity("iexcl") -> 16#000A1; +entity("iff") -> 16#021D4; +entity("ifr") -> 16#1D526; +entity("igrave") -> 16#000EC; +entity("ii") -> 16#02148; +entity("iiiint") -> 16#02A0C; +entity("iiint") -> 16#0222D; +entity("iinfin") -> 16#029DC; +entity("iiota") -> 16#02129; +entity("ijlig") -> 16#00133; +entity("imacr") -> 16#0012B; +entity("image") -> 16#02111; +entity("imagline") -> 16#02110; +entity("imagpart") -> 16#02111; +entity("imath") -> 16#00131; +entity("imof") -> 16#022B7; +entity("imped") -> 16#001B5; +entity("in") -> 16#02208; +entity("incare") -> 16#02105; +entity("infin") -> 16#0221E; +entity("infintie") -> 16#029DD; +entity("inodot") -> 16#00131; +entity("int") -> 16#0222B; +entity("intcal") -> 16#022BA; +entity("integers") -> 16#02124; +entity("intercal") -> 16#022BA; +entity("intlarhk") -> 16#02A17; +entity("intprod") -> 16#02A3C; +entity("iocy") -> 16#00451; +entity("iogon") -> 16#0012F; +entity("iopf") -> 16#1D55A; +entity("iota") -> 16#003B9; +entity("iprod") -> 16#02A3C; +entity("iquest") -> 16#000BF; +entity("iscr") -> 16#1D4BE; +entity("isin") -> 16#02208; +entity("isinE") -> 16#022F9; +entity("isindot") -> 16#022F5; +entity("isins") -> 16#022F4; +entity("isinsv") -> 16#022F3; +entity("isinv") -> 16#02208; +entity("it") -> 16#02062; +entity("itilde") -> 16#00129; +entity("iukcy") -> 16#00456; +entity("iuml") -> 16#000EF; +entity("jcirc") -> 16#00135; +entity("jcy") -> 16#00439; +entity("jfr") -> 16#1D527; +entity("jmath") -> 16#00237; +entity("jopf") -> 16#1D55B; +entity("jscr") -> 16#1D4BF; +entity("jsercy") -> 16#00458; +entity("jukcy") -> 16#00454; +entity("kappa") -> 16#003BA; +entity("kappav") -> 16#003F0; +entity("kcedil") -> 16#00137; +entity("kcy") -> 16#0043A; +entity("kfr") -> 16#1D528; +entity("kgreen") -> 16#00138; +entity("khcy") -> 16#00445; +entity("kjcy") -> 16#0045C; +entity("kopf") -> 16#1D55C; +entity("kscr") -> 16#1D4C0; +entity("lAarr") -> 16#021DA; +entity("lArr") -> 16#021D0; +entity("lAtail") -> 16#0291B; +entity("lBarr") -> 16#0290E; +entity("lE") -> 16#02266; +entity("lEg") -> 16#02A8B; +entity("lHar") -> 16#02962; +entity("lacute") -> 16#0013A; +entity("laemptyv") -> 16#029B4; +entity("lagran") -> 16#02112; +entity("lambda") -> 16#003BB; +entity("lang") -> 16#027E8; +entity("langd") -> 16#02991; +entity("langle") -> 16#027E8; +entity("lap") -> 16#02A85; +entity("laquo") -> 16#000AB; +entity("larr") -> 16#02190; +entity("larrb") -> 16#021E4; +entity("larrbfs") -> 16#0291F; +entity("larrfs") -> 16#0291D; +entity("larrhk") -> 16#021A9; +entity("larrlp") -> 16#021AB; +entity("larrpl") -> 16#02939; +entity("larrsim") -> 16#02973; +entity("larrtl") -> 16#021A2; +entity("lat") -> 16#02AAB; +entity("latail") -> 16#02919; +entity("late") -> 16#02AAD; +entity("lates") -> [16#02AAD, 16#0FE00]; +entity("lbarr") -> 16#0290C; +entity("lbbrk") -> 16#02772; +entity("lbrace") -> 16#0007B; +entity("lbrack") -> 16#0005B; +entity("lbrke") -> 16#0298B; +entity("lbrksld") -> 16#0298F; +entity("lbrkslu") -> 16#0298D; +entity("lcaron") -> 16#0013E; +entity("lcedil") -> 16#0013C; +entity("lceil") -> 16#02308; +entity("lcub") -> 16#0007B; +entity("lcy") -> 16#0043B; +entity("ldca") -> 16#02936; +entity("ldquo") -> 16#0201C; +entity("ldquor") -> 16#0201E; +entity("ldrdhar") -> 16#02967; +entity("ldrushar") -> 16#0294B; +entity("ldsh") -> 16#021B2; +entity("le") -> 16#02264; +entity("leftarrow") -> 16#02190; +entity("leftarrowtail") -> 16#021A2; +entity("leftharpoondown") -> 16#021BD; +entity("leftharpoonup") -> 16#021BC; +entity("leftleftarrows") -> 16#021C7; +entity("leftrightarrow") -> 16#02194; +entity("leftrightarrows") -> 16#021C6; +entity("leftrightharpoons") -> 16#021CB; +entity("leftrightsquigarrow") -> 16#021AD; +entity("leftthreetimes") -> 16#022CB; +entity("leg") -> 16#022DA; +entity("leq") -> 16#02264; +entity("leqq") -> 16#02266; +entity("leqslant") -> 16#02A7D; +entity("les") -> 16#02A7D; +entity("lescc") -> 16#02AA8; +entity("lesdot") -> 16#02A7F; +entity("lesdoto") -> 16#02A81; +entity("lesdotor") -> 16#02A83; +entity("lesg") -> [16#022DA, 16#0FE00]; +entity("lesges") -> 16#02A93; +entity("lessapprox") -> 16#02A85; +entity("lessdot") -> 16#022D6; +entity("lesseqgtr") -> 16#022DA; +entity("lesseqqgtr") -> 16#02A8B; +entity("lessgtr") -> 16#02276; +entity("lesssim") -> 16#02272; +entity("lfisht") -> 16#0297C; +entity("lfloor") -> 16#0230A; +entity("lfr") -> 16#1D529; +entity("lg") -> 16#02276; +entity("lgE") -> 16#02A91; +entity("lhard") -> 16#021BD; +entity("lharu") -> 16#021BC; +entity("lharul") -> 16#0296A; +entity("lhblk") -> 16#02584; +entity("ljcy") -> 16#00459; +entity("ll") -> 16#0226A; +entity("llarr") -> 16#021C7; +entity("llcorner") -> 16#0231E; +entity("llhard") -> 16#0296B; +entity("lltri") -> 16#025FA; +entity("lmidot") -> 16#00140; +entity("lmoust") -> 16#023B0; +entity("lmoustache") -> 16#023B0; +entity("lnE") -> 16#02268; +entity("lnap") -> 16#02A89; +entity("lnapprox") -> 16#02A89; +entity("lne") -> 16#02A87; +entity("lneq") -> 16#02A87; +entity("lneqq") -> 16#02268; +entity("lnsim") -> 16#022E6; +entity("loang") -> 16#027EC; +entity("loarr") -> 16#021FD; +entity("lobrk") -> 16#027E6; +entity("longleftarrow") -> 16#027F5; +entity("longleftrightarrow") -> 16#027F7; +entity("longmapsto") -> 16#027FC; +entity("longrightarrow") -> 16#027F6; +entity("looparrowleft") -> 16#021AB; +entity("looparrowright") -> 16#021AC; +entity("lopar") -> 16#02985; +entity("lopf") -> 16#1D55D; +entity("loplus") -> 16#02A2D; +entity("lotimes") -> 16#02A34; +entity("lowast") -> 16#02217; +entity("lowbar") -> 16#0005F; +entity("loz") -> 16#025CA; +entity("lozenge") -> 16#025CA; +entity("lozf") -> 16#029EB; +entity("lpar") -> 16#00028; +entity("lparlt") -> 16#02993; +entity("lrarr") -> 16#021C6; +entity("lrcorner") -> 16#0231F; +entity("lrhar") -> 16#021CB; +entity("lrhard") -> 16#0296D; +entity("lrm") -> 16#0200E; +entity("lrtri") -> 16#022BF; +entity("lsaquo") -> 16#02039; +entity("lscr") -> 16#1D4C1; +entity("lsh") -> 16#021B0; +entity("lsim") -> 16#02272; +entity("lsime") -> 16#02A8D; +entity("lsimg") -> 16#02A8F; +entity("lsqb") -> 16#0005B; +entity("lsquo") -> 16#02018; +entity("lsquor") -> 16#0201A; +entity("lstrok") -> 16#00142; +entity("lt") -> 16#0003C; +entity("ltcc") -> 16#02AA6; +entity("ltcir") -> 16#02A79; +entity("ltdot") -> 16#022D6; +entity("lthree") -> 16#022CB; +entity("ltimes") -> 16#022C9; +entity("ltlarr") -> 16#02976; +entity("ltquest") -> 16#02A7B; +entity("ltrPar") -> 16#02996; +entity("ltri") -> 16#025C3; +entity("ltrie") -> 16#022B4; +entity("ltrif") -> 16#025C2; +entity("lurdshar") -> 16#0294A; +entity("luruhar") -> 16#02966; +entity("lvertneqq") -> [16#02268, 16#0FE00]; +entity("lvnE") -> [16#02268, 16#0FE00]; +entity("mDDot") -> 16#0223A; +entity("macr") -> 16#000AF; +entity("male") -> 16#02642; +entity("malt") -> 16#02720; +entity("maltese") -> 16#02720; +entity("map") -> 16#021A6; +entity("mapsto") -> 16#021A6; +entity("mapstodown") -> 16#021A7; +entity("mapstoleft") -> 16#021A4; +entity("mapstoup") -> 16#021A5; +entity("marker") -> 16#025AE; +entity("mcomma") -> 16#02A29; +entity("mcy") -> 16#0043C; +entity("mdash") -> 16#02014; +entity("measuredangle") -> 16#02221; +entity("mfr") -> 16#1D52A; +entity("mho") -> 16#02127; +entity("micro") -> 16#000B5; +entity("mid") -> 16#02223; +entity("midast") -> 16#0002A; +entity("midcir") -> 16#02AF0; +entity("middot") -> 16#000B7; +entity("minus") -> 16#02212; +entity("minusb") -> 16#0229F; +entity("minusd") -> 16#02238; +entity("minusdu") -> 16#02A2A; +entity("mlcp") -> 16#02ADB; +entity("mldr") -> 16#02026; +entity("mnplus") -> 16#02213; +entity("models") -> 16#022A7; +entity("mopf") -> 16#1D55E; +entity("mp") -> 16#02213; +entity("mscr") -> 16#1D4C2; +entity("mstpos") -> 16#0223E; +entity("mu") -> 16#003BC; +entity("multimap") -> 16#022B8; +entity("mumap") -> 16#022B8; +entity("nGg") -> [16#022D9, 16#00338]; +entity("nGt") -> [16#0226B, 16#020D2]; +entity("nGtv") -> [16#0226B, 16#00338]; +entity("nLeftarrow") -> 16#021CD; +entity("nLeftrightarrow") -> 16#021CE; +entity("nLl") -> [16#022D8, 16#00338]; +entity("nLt") -> [16#0226A, 16#020D2]; +entity("nLtv") -> [16#0226A, 16#00338]; +entity("nRightarrow") -> 16#021CF; +entity("nVDash") -> 16#022AF; +entity("nVdash") -> 16#022AE; +entity("nabla") -> 16#02207; +entity("nacute") -> 16#00144; +entity("nang") -> [16#02220, 16#020D2]; +entity("nap") -> 16#02249; +entity("napE") -> [16#02A70, 16#00338]; +entity("napid") -> [16#0224B, 16#00338]; +entity("napos") -> 16#00149; +entity("napprox") -> 16#02249; +entity("natur") -> 16#0266E; +entity("natural") -> 16#0266E; +entity("naturals") -> 16#02115; +entity("nbsp") -> 16#000A0; +entity("nbump") -> [16#0224E, 16#00338]; +entity("nbumpe") -> [16#0224F, 16#00338]; +entity("ncap") -> 16#02A43; +entity("ncaron") -> 16#00148; +entity("ncedil") -> 16#00146; +entity("ncong") -> 16#02247; +entity("ncongdot") -> [16#02A6D, 16#00338]; +entity("ncup") -> 16#02A42; +entity("ncy") -> 16#0043D; +entity("ndash") -> 16#02013; +entity("ne") -> 16#02260; +entity("neArr") -> 16#021D7; +entity("nearhk") -> 16#02924; +entity("nearr") -> 16#02197; +entity("nearrow") -> 16#02197; +entity("nedot") -> [16#02250, 16#00338]; +entity("nequiv") -> 16#02262; +entity("nesear") -> 16#02928; +entity("nesim") -> [16#02242, 16#00338]; +entity("nexist") -> 16#02204; +entity("nexists") -> 16#02204; +entity("nfr") -> 16#1D52B; +entity("ngE") -> [16#02267, 16#00338]; +entity("nge") -> 16#02271; +entity("ngeq") -> 16#02271; +entity("ngeqq") -> [16#02267, 16#00338]; +entity("ngeqslant") -> [16#02A7E, 16#00338]; +entity("nges") -> [16#02A7E, 16#00338]; +entity("ngsim") -> 16#02275; +entity("ngt") -> 16#0226F; +entity("ngtr") -> 16#0226F; +entity("nhArr") -> 16#021CE; +entity("nharr") -> 16#021AE; +entity("nhpar") -> 16#02AF2; +entity("ni") -> 16#0220B; +entity("nis") -> 16#022FC; +entity("nisd") -> 16#022FA; +entity("niv") -> 16#0220B; +entity("njcy") -> 16#0045A; +entity("nlArr") -> 16#021CD; +entity("nlE") -> [16#02266, 16#00338]; +entity("nlarr") -> 16#0219A; +entity("nldr") -> 16#02025; +entity("nle") -> 16#02270; +entity("nleftarrow") -> 16#0219A; +entity("nleftrightarrow") -> 16#021AE; +entity("nleq") -> 16#02270; +entity("nleqq") -> [16#02266, 16#00338]; +entity("nleqslant") -> [16#02A7D, 16#00338]; +entity("nles") -> [16#02A7D, 16#00338]; +entity("nless") -> 16#0226E; +entity("nlsim") -> 16#02274; +entity("nlt") -> 16#0226E; +entity("nltri") -> 16#022EA; +entity("nltrie") -> 16#022EC; +entity("nmid") -> 16#02224; +entity("nopf") -> 16#1D55F; +entity("not") -> 16#000AC; +entity("notin") -> 16#02209; +entity("notinE") -> [16#022F9, 16#00338]; +entity("notindot") -> [16#022F5, 16#00338]; +entity("notinva") -> 16#02209; +entity("notinvb") -> 16#022F7; +entity("notinvc") -> 16#022F6; +entity("notni") -> 16#0220C; +entity("notniva") -> 16#0220C; +entity("notnivb") -> 16#022FE; +entity("notnivc") -> 16#022FD; +entity("npar") -> 16#02226; +entity("nparallel") -> 16#02226; +entity("nparsl") -> [16#02AFD, 16#020E5]; +entity("npart") -> [16#02202, 16#00338]; +entity("npolint") -> 16#02A14; +entity("npr") -> 16#02280; +entity("nprcue") -> 16#022E0; +entity("npre") -> [16#02AAF, 16#00338]; +entity("nprec") -> 16#02280; +entity("npreceq") -> [16#02AAF, 16#00338]; +entity("nrArr") -> 16#021CF; +entity("nrarr") -> 16#0219B; +entity("nrarrc") -> [16#02933, 16#00338]; +entity("nrarrw") -> [16#0219D, 16#00338]; +entity("nrightarrow") -> 16#0219B; +entity("nrtri") -> 16#022EB; +entity("nrtrie") -> 16#022ED; +entity("nsc") -> 16#02281; +entity("nsccue") -> 16#022E1; +entity("nsce") -> [16#02AB0, 16#00338]; +entity("nscr") -> 16#1D4C3; +entity("nshortmid") -> 16#02224; +entity("nshortparallel") -> 16#02226; +entity("nsim") -> 16#02241; +entity("nsime") -> 16#02244; +entity("nsimeq") -> 16#02244; +entity("nsmid") -> 16#02224; +entity("nspar") -> 16#02226; +entity("nsqsube") -> 16#022E2; +entity("nsqsupe") -> 16#022E3; +entity("nsub") -> 16#02284; +entity("nsubE") -> [16#02AC5, 16#00338]; +entity("nsube") -> 16#02288; +entity("nsubset") -> [16#02282, 16#020D2]; +entity("nsubseteq") -> 16#02288; +entity("nsubseteqq") -> [16#02AC5, 16#00338]; +entity("nsucc") -> 16#02281; +entity("nsucceq") -> [16#02AB0, 16#00338]; +entity("nsup") -> 16#02285; +entity("nsupE") -> [16#02AC6, 16#00338]; +entity("nsupe") -> 16#02289; +entity("nsupset") -> [16#02283, 16#020D2]; +entity("nsupseteq") -> 16#02289; +entity("nsupseteqq") -> [16#02AC6, 16#00338]; +entity("ntgl") -> 16#02279; +entity("ntilde") -> 16#000F1; +entity("ntlg") -> 16#02278; +entity("ntriangleleft") -> 16#022EA; +entity("ntrianglelefteq") -> 16#022EC; +entity("ntriangleright") -> 16#022EB; +entity("ntrianglerighteq") -> 16#022ED; +entity("nu") -> 16#003BD; +entity("num") -> 16#00023; +entity("numero") -> 16#02116; +entity("numsp") -> 16#02007; +entity("nvDash") -> 16#022AD; +entity("nvHarr") -> 16#02904; +entity("nvap") -> [16#0224D, 16#020D2]; +entity("nvdash") -> 16#022AC; +entity("nvge") -> [16#02265, 16#020D2]; +entity("nvgt") -> [16#0003E, 16#020D2]; +entity("nvinfin") -> 16#029DE; +entity("nvlArr") -> 16#02902; +entity("nvle") -> [16#02264, 16#020D2]; +entity("nvlt") -> [16#0003C, 16#020D2]; +entity("nvltrie") -> [16#022B4, 16#020D2]; +entity("nvrArr") -> 16#02903; +entity("nvrtrie") -> [16#022B5, 16#020D2]; +entity("nvsim") -> [16#0223C, 16#020D2]; +entity("nwArr") -> 16#021D6; +entity("nwarhk") -> 16#02923; +entity("nwarr") -> 16#02196; +entity("nwarrow") -> 16#02196; +entity("nwnear") -> 16#02927; +entity("oS") -> 16#024C8; +entity("oacute") -> 16#000F3; +entity("oast") -> 16#0229B; +entity("ocir") -> 16#0229A; +entity("ocirc") -> 16#000F4; +entity("ocy") -> 16#0043E; +entity("odash") -> 16#0229D; +entity("odblac") -> 16#00151; +entity("odiv") -> 16#02A38; +entity("odot") -> 16#02299; +entity("odsold") -> 16#029BC; +entity("oelig") -> 16#00153; +entity("ofcir") -> 16#029BF; +entity("ofr") -> 16#1D52C; +entity("ogon") -> 16#002DB; +entity("ograve") -> 16#000F2; +entity("ogt") -> 16#029C1; +entity("ohbar") -> 16#029B5; +entity("ohm") -> 16#003A9; +entity("oint") -> 16#0222E; +entity("olarr") -> 16#021BA; +entity("olcir") -> 16#029BE; +entity("olcross") -> 16#029BB; +entity("oline") -> 16#0203E; +entity("olt") -> 16#029C0; +entity("omacr") -> 16#0014D; +entity("omega") -> 16#003C9; +entity("omicron") -> 16#003BF; +entity("omid") -> 16#029B6; +entity("ominus") -> 16#02296; +entity("oopf") -> 16#1D560; +entity("opar") -> 16#029B7; +entity("operp") -> 16#029B9; +entity("oplus") -> 16#02295; +entity("or") -> 16#02228; +entity("orarr") -> 16#021BB; +entity("ord") -> 16#02A5D; +entity("order") -> 16#02134; +entity("orderof") -> 16#02134; +entity("ordf") -> 16#000AA; +entity("ordm") -> 16#000BA; +entity("origof") -> 16#022B6; +entity("oror") -> 16#02A56; +entity("orslope") -> 16#02A57; +entity("orv") -> 16#02A5B; +entity("oscr") -> 16#02134; +entity("oslash") -> 16#000F8; +entity("osol") -> 16#02298; +entity("otilde") -> 16#000F5; +entity("otimes") -> 16#02297; +entity("otimesas") -> 16#02A36; +entity("ouml") -> 16#000F6; +entity("ovbar") -> 16#0233D; +entity("par") -> 16#02225; +entity("para") -> 16#000B6; +entity("parallel") -> 16#02225; +entity("parsim") -> 16#02AF3; +entity("parsl") -> 16#02AFD; +entity("part") -> 16#02202; +entity("pcy") -> 16#0043F; +entity("percnt") -> 16#00025; +entity("period") -> 16#0002E; +entity("permil") -> 16#02030; +entity("perp") -> 16#022A5; +entity("pertenk") -> 16#02031; +entity("pfr") -> 16#1D52D; +entity("phi") -> 16#003C6; +entity("phiv") -> 16#003D5; +entity("phmmat") -> 16#02133; +entity("phone") -> 16#0260E; +entity("pi") -> 16#003C0; +entity("pitchfork") -> 16#022D4; +entity("piv") -> 16#003D6; +entity("planck") -> 16#0210F; +entity("planckh") -> 16#0210E; +entity("plankv") -> 16#0210F; +entity("plus") -> 16#0002B; +entity("plusacir") -> 16#02A23; +entity("plusb") -> 16#0229E; +entity("pluscir") -> 16#02A22; +entity("plusdo") -> 16#02214; +entity("plusdu") -> 16#02A25; +entity("pluse") -> 16#02A72; +entity("plusmn") -> 16#000B1; +entity("plussim") -> 16#02A26; +entity("plustwo") -> 16#02A27; +entity("pm") -> 16#000B1; +entity("pointint") -> 16#02A15; +entity("popf") -> 16#1D561; +entity("pound") -> 16#000A3; +entity("pr") -> 16#0227A; +entity("prE") -> 16#02AB3; +entity("prap") -> 16#02AB7; +entity("prcue") -> 16#0227C; +entity("pre") -> 16#02AAF; +entity("prec") -> 16#0227A; +entity("precapprox") -> 16#02AB7; +entity("preccurlyeq") -> 16#0227C; +entity("preceq") -> 16#02AAF; +entity("precnapprox") -> 16#02AB9; +entity("precneqq") -> 16#02AB5; +entity("precnsim") -> 16#022E8; +entity("precsim") -> 16#0227E; +entity("prime") -> 16#02032; +entity("primes") -> 16#02119; +entity("prnE") -> 16#02AB5; +entity("prnap") -> 16#02AB9; +entity("prnsim") -> 16#022E8; +entity("prod") -> 16#0220F; +entity("profalar") -> 16#0232E; +entity("profline") -> 16#02312; +entity("profsurf") -> 16#02313; +entity("prop") -> 16#0221D; +entity("propto") -> 16#0221D; +entity("prsim") -> 16#0227E; +entity("prurel") -> 16#022B0; +entity("pscr") -> 16#1D4C5; +entity("psi") -> 16#003C8; +entity("puncsp") -> 16#02008; +entity("qfr") -> 16#1D52E; +entity("qint") -> 16#02A0C; +entity("qopf") -> 16#1D562; +entity("qprime") -> 16#02057; +entity("qscr") -> 16#1D4C6; +entity("quaternions") -> 16#0210D; +entity("quatint") -> 16#02A16; +entity("quest") -> 16#0003F; +entity("questeq") -> 16#0225F; +entity("quot") -> 16#00022; +entity("rAarr") -> 16#021DB; +entity("rArr") -> 16#021D2; +entity("rAtail") -> 16#0291C; +entity("rBarr") -> 16#0290F; +entity("rHar") -> 16#02964; +entity("race") -> [16#0223D, 16#00331]; +entity("racute") -> 16#00155; +entity("radic") -> 16#0221A; +entity("raemptyv") -> 16#029B3; +entity("rang") -> 16#027E9; +entity("rangd") -> 16#02992; +entity("range") -> 16#029A5; +entity("rangle") -> 16#027E9; +entity("raquo") -> 16#000BB; +entity("rarr") -> 16#02192; +entity("rarrap") -> 16#02975; +entity("rarrb") -> 16#021E5; +entity("rarrbfs") -> 16#02920; +entity("rarrc") -> 16#02933; +entity("rarrfs") -> 16#0291E; +entity("rarrhk") -> 16#021AA; +entity("rarrlp") -> 16#021AC; +entity("rarrpl") -> 16#02945; +entity("rarrsim") -> 16#02974; +entity("rarrtl") -> 16#021A3; +entity("rarrw") -> 16#0219D; +entity("ratail") -> 16#0291A; +entity("ratio") -> 16#02236; +entity("rationals") -> 16#0211A; +entity("rbarr") -> 16#0290D; +entity("rbbrk") -> 16#02773; +entity("rbrace") -> 16#0007D; +entity("rbrack") -> 16#0005D; +entity("rbrke") -> 16#0298C; +entity("rbrksld") -> 16#0298E; +entity("rbrkslu") -> 16#02990; +entity("rcaron") -> 16#00159; +entity("rcedil") -> 16#00157; +entity("rceil") -> 16#02309; +entity("rcub") -> 16#0007D; +entity("rcy") -> 16#00440; +entity("rdca") -> 16#02937; +entity("rdldhar") -> 16#02969; +entity("rdquo") -> 16#0201D; +entity("rdquor") -> 16#0201D; +entity("rdsh") -> 16#021B3; +entity("real") -> 16#0211C; +entity("realine") -> 16#0211B; +entity("realpart") -> 16#0211C; +entity("reals") -> 16#0211D; +entity("rect") -> 16#025AD; +entity("reg") -> 16#000AE; +entity("rfisht") -> 16#0297D; +entity("rfloor") -> 16#0230B; +entity("rfr") -> 16#1D52F; +entity("rhard") -> 16#021C1; +entity("rharu") -> 16#021C0; +entity("rharul") -> 16#0296C; +entity("rho") -> 16#003C1; +entity("rhov") -> 16#003F1; +entity("rightarrow") -> 16#02192; +entity("rightarrowtail") -> 16#021A3; +entity("rightharpoondown") -> 16#021C1; +entity("rightharpoonup") -> 16#021C0; +entity("rightleftarrows") -> 16#021C4; +entity("rightleftharpoons") -> 16#021CC; +entity("rightrightarrows") -> 16#021C9; +entity("rightsquigarrow") -> 16#0219D; +entity("rightthreetimes") -> 16#022CC; +entity("ring") -> 16#002DA; +entity("risingdotseq") -> 16#02253; +entity("rlarr") -> 16#021C4; +entity("rlhar") -> 16#021CC; +entity("rlm") -> 16#0200F; +entity("rmoust") -> 16#023B1; +entity("rmoustache") -> 16#023B1; +entity("rnmid") -> 16#02AEE; +entity("roang") -> 16#027ED; +entity("roarr") -> 16#021FE; +entity("robrk") -> 16#027E7; +entity("ropar") -> 16#02986; +entity("ropf") -> 16#1D563; +entity("roplus") -> 16#02A2E; +entity("rotimes") -> 16#02A35; +entity("rpar") -> 16#00029; +entity("rpargt") -> 16#02994; +entity("rppolint") -> 16#02A12; +entity("rrarr") -> 16#021C9; +entity("rsaquo") -> 16#0203A; +entity("rscr") -> 16#1D4C7; +entity("rsh") -> 16#021B1; +entity("rsqb") -> 16#0005D; +entity("rsquo") -> 16#02019; +entity("rsquor") -> 16#02019; +entity("rthree") -> 16#022CC; +entity("rtimes") -> 16#022CA; +entity("rtri") -> 16#025B9; +entity("rtrie") -> 16#022B5; +entity("rtrif") -> 16#025B8; +entity("rtriltri") -> 16#029CE; +entity("ruluhar") -> 16#02968; +entity("rx") -> 16#0211E; +entity("sacute") -> 16#0015B; +entity("sbquo") -> 16#0201A; +entity("sc") -> 16#0227B; +entity("scE") -> 16#02AB4; +entity("scap") -> 16#02AB8; +entity("scaron") -> 16#00161; +entity("sccue") -> 16#0227D; +entity("sce") -> 16#02AB0; +entity("scedil") -> 16#0015F; +entity("scirc") -> 16#0015D; +entity("scnE") -> 16#02AB6; +entity("scnap") -> 16#02ABA; +entity("scnsim") -> 16#022E9; +entity("scpolint") -> 16#02A13; +entity("scsim") -> 16#0227F; +entity("scy") -> 16#00441; +entity("sdot") -> 16#022C5; +entity("sdotb") -> 16#022A1; +entity("sdote") -> 16#02A66; +entity("seArr") -> 16#021D8; +entity("searhk") -> 16#02925; +entity("searr") -> 16#02198; +entity("searrow") -> 16#02198; +entity("sect") -> 16#000A7; +entity("semi") -> 16#0003B; +entity("seswar") -> 16#02929; +entity("setminus") -> 16#02216; +entity("setmn") -> 16#02216; +entity("sext") -> 16#02736; +entity("sfr") -> 16#1D530; +entity("sfrown") -> 16#02322; +entity("sharp") -> 16#0266F; +entity("shchcy") -> 16#00449; +entity("shcy") -> 16#00448; +entity("shortmid") -> 16#02223; +entity("shortparallel") -> 16#02225; +entity("shy") -> 16#000AD; +entity("sigma") -> 16#003C3; +entity("sigmaf") -> 16#003C2; +entity("sigmav") -> 16#003C2; +entity("sim") -> 16#0223C; +entity("simdot") -> 16#02A6A; +entity("sime") -> 16#02243; +entity("simeq") -> 16#02243; +entity("simg") -> 16#02A9E; +entity("simgE") -> 16#02AA0; +entity("siml") -> 16#02A9D; +entity("simlE") -> 16#02A9F; +entity("simne") -> 16#02246; +entity("simplus") -> 16#02A24; +entity("simrarr") -> 16#02972; +entity("slarr") -> 16#02190; +entity("smallsetminus") -> 16#02216; +entity("smashp") -> 16#02A33; +entity("smeparsl") -> 16#029E4; +entity("smid") -> 16#02223; +entity("smile") -> 16#02323; +entity("smt") -> 16#02AAA; +entity("smte") -> 16#02AAC; +entity("smtes") -> [16#02AAC, 16#0FE00]; +entity("softcy") -> 16#0044C; +entity("sol") -> 16#0002F; +entity("solb") -> 16#029C4; +entity("solbar") -> 16#0233F; +entity("sopf") -> 16#1D564; +entity("spades") -> 16#02660; +entity("spadesuit") -> 16#02660; +entity("spar") -> 16#02225; +entity("sqcap") -> 16#02293; +entity("sqcaps") -> [16#02293, 16#0FE00]; +entity("sqcup") -> 16#02294; +entity("sqcups") -> [16#02294, 16#0FE00]; +entity("sqsub") -> 16#0228F; +entity("sqsube") -> 16#02291; +entity("sqsubset") -> 16#0228F; +entity("sqsubseteq") -> 16#02291; +entity("sqsup") -> 16#02290; +entity("sqsupe") -> 16#02292; +entity("sqsupset") -> 16#02290; +entity("sqsupseteq") -> 16#02292; +entity("squ") -> 16#025A1; +entity("square") -> 16#025A1; +entity("squarf") -> 16#025AA; +entity("squf") -> 16#025AA; +entity("srarr") -> 16#02192; +entity("sscr") -> 16#1D4C8; +entity("ssetmn") -> 16#02216; +entity("ssmile") -> 16#02323; +entity("sstarf") -> 16#022C6; +entity("star") -> 16#02606; +entity("starf") -> 16#02605; +entity("straightepsilon") -> 16#003F5; +entity("straightphi") -> 16#003D5; +entity("strns") -> 16#000AF; +entity("sub") -> 16#02282; +entity("subE") -> 16#02AC5; +entity("subdot") -> 16#02ABD; +entity("sube") -> 16#02286; +entity("subedot") -> 16#02AC3; +entity("submult") -> 16#02AC1; +entity("subnE") -> 16#02ACB; +entity("subne") -> 16#0228A; +entity("subplus") -> 16#02ABF; +entity("subrarr") -> 16#02979; +entity("subset") -> 16#02282; +entity("subseteq") -> 16#02286; +entity("subseteqq") -> 16#02AC5; +entity("subsetneq") -> 16#0228A; +entity("subsetneqq") -> 16#02ACB; +entity("subsim") -> 16#02AC7; +entity("subsub") -> 16#02AD5; +entity("subsup") -> 16#02AD3; +entity("succ") -> 16#0227B; +entity("succapprox") -> 16#02AB8; +entity("succcurlyeq") -> 16#0227D; +entity("succeq") -> 16#02AB0; +entity("succnapprox") -> 16#02ABA; +entity("succneqq") -> 16#02AB6; +entity("succnsim") -> 16#022E9; +entity("succsim") -> 16#0227F; +entity("sum") -> 16#02211; +entity("sung") -> 16#0266A; +entity("sup") -> 16#02283; +entity("sup1") -> 16#000B9; +entity("sup2") -> 16#000B2; +entity("sup3") -> 16#000B3; +entity("supE") -> 16#02AC6; +entity("supdot") -> 16#02ABE; +entity("supdsub") -> 16#02AD8; +entity("supe") -> 16#02287; +entity("supedot") -> 16#02AC4; +entity("suphsol") -> 16#027C9; +entity("suphsub") -> 16#02AD7; +entity("suplarr") -> 16#0297B; +entity("supmult") -> 16#02AC2; +entity("supnE") -> 16#02ACC; +entity("supne") -> 16#0228B; +entity("supplus") -> 16#02AC0; +entity("supset") -> 16#02283; +entity("supseteq") -> 16#02287; +entity("supseteqq") -> 16#02AC6; +entity("supsetneq") -> 16#0228B; +entity("supsetneqq") -> 16#02ACC; +entity("supsim") -> 16#02AC8; +entity("supsub") -> 16#02AD4; +entity("supsup") -> 16#02AD6; +entity("swArr") -> 16#021D9; +entity("swarhk") -> 16#02926; +entity("swarr") -> 16#02199; +entity("swarrow") -> 16#02199; +entity("swnwar") -> 16#0292A; +entity("szlig") -> 16#000DF; +entity("target") -> 16#02316; +entity("tau") -> 16#003C4; +entity("tbrk") -> 16#023B4; +entity("tcaron") -> 16#00165; +entity("tcedil") -> 16#00163; +entity("tcy") -> 16#00442; +entity("tdot") -> 16#020DB; +entity("telrec") -> 16#02315; +entity("tfr") -> 16#1D531; +entity("there4") -> 16#02234; +entity("therefore") -> 16#02234; +entity("theta") -> 16#003B8; +entity("thetasym") -> 16#003D1; +entity("thetav") -> 16#003D1; +entity("thickapprox") -> 16#02248; +entity("thicksim") -> 16#0223C; +entity("thinsp") -> 16#02009; +entity("thkap") -> 16#02248; +entity("thksim") -> 16#0223C; +entity("thorn") -> 16#000FE; +entity("tilde") -> 16#002DC; +entity("times") -> 16#000D7; +entity("timesb") -> 16#022A0; +entity("timesbar") -> 16#02A31; +entity("timesd") -> 16#02A30; +entity("tint") -> 16#0222D; +entity("toea") -> 16#02928; +entity("top") -> 16#022A4; +entity("topbot") -> 16#02336; +entity("topcir") -> 16#02AF1; +entity("topf") -> 16#1D565; +entity("topfork") -> 16#02ADA; +entity("tosa") -> 16#02929; +entity("tprime") -> 16#02034; +entity("trade") -> 16#02122; +entity("triangle") -> 16#025B5; +entity("triangledown") -> 16#025BF; +entity("triangleleft") -> 16#025C3; +entity("trianglelefteq") -> 16#022B4; +entity("triangleq") -> 16#0225C; +entity("triangleright") -> 16#025B9; +entity("trianglerighteq") -> 16#022B5; +entity("tridot") -> 16#025EC; +entity("trie") -> 16#0225C; +entity("triminus") -> 16#02A3A; +entity("triplus") -> 16#02A39; +entity("trisb") -> 16#029CD; +entity("tritime") -> 16#02A3B; +entity("trpezium") -> 16#023E2; +entity("tscr") -> 16#1D4C9; +entity("tscy") -> 16#00446; +entity("tshcy") -> 16#0045B; +entity("tstrok") -> 16#00167; +entity("twixt") -> 16#0226C; +entity("twoheadleftarrow") -> 16#0219E; +entity("twoheadrightarrow") -> 16#021A0; +entity("uArr") -> 16#021D1; +entity("uHar") -> 16#02963; +entity("uacute") -> 16#000FA; +entity("uarr") -> 16#02191; +entity("ubrcy") -> 16#0045E; +entity("ubreve") -> 16#0016D; +entity("ucirc") -> 16#000FB; +entity("ucy") -> 16#00443; +entity("udarr") -> 16#021C5; +entity("udblac") -> 16#00171; +entity("udhar") -> 16#0296E; +entity("ufisht") -> 16#0297E; +entity("ufr") -> 16#1D532; +entity("ugrave") -> 16#000F9; +entity("uharl") -> 16#021BF; +entity("uharr") -> 16#021BE; +entity("uhblk") -> 16#02580; +entity("ulcorn") -> 16#0231C; +entity("ulcorner") -> 16#0231C; +entity("ulcrop") -> 16#0230F; +entity("ultri") -> 16#025F8; +entity("umacr") -> 16#0016B; +entity("uml") -> 16#000A8; +entity("uogon") -> 16#00173; +entity("uopf") -> 16#1D566; +entity("uparrow") -> 16#02191; +entity("updownarrow") -> 16#02195; +entity("upharpoonleft") -> 16#021BF; +entity("upharpoonright") -> 16#021BE; +entity("uplus") -> 16#0228E; +entity("upsi") -> 16#003C5; +entity("upsih") -> 16#003D2; +entity("upsilon") -> 16#003C5; +entity("upuparrows") -> 16#021C8; +entity("urcorn") -> 16#0231D; +entity("urcorner") -> 16#0231D; +entity("urcrop") -> 16#0230E; +entity("uring") -> 16#0016F; +entity("urtri") -> 16#025F9; +entity("uscr") -> 16#1D4CA; +entity("utdot") -> 16#022F0; +entity("utilde") -> 16#00169; +entity("utri") -> 16#025B5; +entity("utrif") -> 16#025B4; +entity("uuarr") -> 16#021C8; +entity("uuml") -> 16#000FC; +entity("uwangle") -> 16#029A7; +entity("vArr") -> 16#021D5; +entity("vBar") -> 16#02AE8; +entity("vBarv") -> 16#02AE9; +entity("vDash") -> 16#022A8; +entity("vangrt") -> 16#0299C; +entity("varepsilon") -> 16#003F5; +entity("varkappa") -> 16#003F0; +entity("varnothing") -> 16#02205; +entity("varphi") -> 16#003D5; +entity("varpi") -> 16#003D6; +entity("varpropto") -> 16#0221D; +entity("varr") -> 16#02195; +entity("varrho") -> 16#003F1; +entity("varsigma") -> 16#003C2; +entity("varsubsetneq") -> [16#0228A, 16#0FE00]; +entity("varsubsetneqq") -> [16#02ACB, 16#0FE00]; +entity("varsupsetneq") -> [16#0228B, 16#0FE00]; +entity("varsupsetneqq") -> [16#02ACC, 16#0FE00]; +entity("vartheta") -> 16#003D1; +entity("vartriangleleft") -> 16#022B2; +entity("vartriangleright") -> 16#022B3; +entity("vcy") -> 16#00432; +entity("vdash") -> 16#022A2; +entity("vee") -> 16#02228; +entity("veebar") -> 16#022BB; +entity("veeeq") -> 16#0225A; +entity("vellip") -> 16#022EE; +entity("verbar") -> 16#0007C; +entity("vert") -> 16#0007C; +entity("vfr") -> 16#1D533; +entity("vltri") -> 16#022B2; +entity("vnsub") -> [16#02282, 16#020D2]; +entity("vnsup") -> [16#02283, 16#020D2]; +entity("vopf") -> 16#1D567; +entity("vprop") -> 16#0221D; +entity("vrtri") -> 16#022B3; +entity("vscr") -> 16#1D4CB; +entity("vsubnE") -> [16#02ACB, 16#0FE00]; +entity("vsubne") -> [16#0228A, 16#0FE00]; +entity("vsupnE") -> [16#02ACC, 16#0FE00]; +entity("vsupne") -> [16#0228B, 16#0FE00]; +entity("vzigzag") -> 16#0299A; +entity("wcirc") -> 16#00175; +entity("wedbar") -> 16#02A5F; +entity("wedge") -> 16#02227; +entity("wedgeq") -> 16#02259; +entity("weierp") -> 16#02118; +entity("wfr") -> 16#1D534; +entity("wopf") -> 16#1D568; +entity("wp") -> 16#02118; +entity("wr") -> 16#02240; +entity("wreath") -> 16#02240; +entity("wscr") -> 16#1D4CC; +entity("xcap") -> 16#022C2; +entity("xcirc") -> 16#025EF; +entity("xcup") -> 16#022C3; +entity("xdtri") -> 16#025BD; +entity("xfr") -> 16#1D535; +entity("xhArr") -> 16#027FA; +entity("xharr") -> 16#027F7; +entity("xi") -> 16#003BE; +entity("xlArr") -> 16#027F8; +entity("xlarr") -> 16#027F5; +entity("xmap") -> 16#027FC; +entity("xnis") -> 16#022FB; +entity("xodot") -> 16#02A00; +entity("xopf") -> 16#1D569; +entity("xoplus") -> 16#02A01; +entity("xotime") -> 16#02A02; +entity("xrArr") -> 16#027F9; +entity("xrarr") -> 16#027F6; +entity("xscr") -> 16#1D4CD; +entity("xsqcup") -> 16#02A06; +entity("xuplus") -> 16#02A04; +entity("xutri") -> 16#025B3; +entity("xvee") -> 16#022C1; +entity("xwedge") -> 16#022C0; +entity("yacute") -> 16#000FD; +entity("yacy") -> 16#0044F; +entity("ycirc") -> 16#00177; +entity("ycy") -> 16#0044B; +entity("yen") -> 16#000A5; +entity("yfr") -> 16#1D536; +entity("yicy") -> 16#00457; +entity("yopf") -> 16#1D56A; +entity("yscr") -> 16#1D4CE; +entity("yucy") -> 16#0044E; +entity("yuml") -> 16#000FF; +entity("zacute") -> 16#0017A; +entity("zcaron") -> 16#0017E; +entity("zcy") -> 16#00437; +entity("zdot") -> 16#0017C; +entity("zeetrf") -> 16#02128; +entity("zeta") -> 16#003B6; +entity("zfr") -> 16#1D537; +entity("zhcy") -> 16#00436; +entity("zigrarr") -> 16#021DD; +entity("zopf") -> 16#1D56B; +entity("zscr") -> 16#1D4CF; +entity("zwj") -> 16#0200D; +entity("zwnj") -> 16#0200C; +entity(_) -> undefined. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +exhaustive_entity_test() -> + T = mochiweb_cover:clause_lookup_table(?MODULE, entity), + [?assertEqual(V, entity(K)) || {K, V} <- T]. + +charref_test() -> + 1234 = charref("#1234"), + 255 = charref("#xfF"), + 255 = charref(<<"#XFf">>), + 38 = charref("amp"), + 38 = charref(<<"amp">>), + undefined = charref("not_an_entity"), + undefined = charref("#not_an_entity"), + undefined = charref("#xnot_an_entity"), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiweb_clock.erl b/deps/mochiweb/src/mochiweb_clock.erl new file mode 100644 index 0000000..4f101c5 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_clock.erl @@ -0,0 +1,101 @@ +%% Copyright (c) 2011-2014, Loïc Hoguin +%% Copyright (c) 2015, Robert Kowalski +%% +%% Permission to use, copy, modify, and/or distribute this software for any +%% purpose with or without fee is hereby granted, provided that the above +%% copyright notice and this permission notice appear in all copies. +%% +%% THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +%% While a gen_server process runs in the background to update +%% the cache of formatted dates every second, all API calls are +%% local and directly read from the ETS cache table, providing +%% fast time and date computations. + +-module(mochiweb_clock). + +-behaviour(gen_server). + +%% API. +-export([start_link/0]). +-export([start/0]). +-export([stop/0]). +-export([rfc1123/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, {}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +-spec start() -> {ok, pid()}. +start() -> + gen_server:start({local, ?MODULE}, ?MODULE, [], []). + +-spec stop() -> stopped. +stop() -> + gen_server:call(?MODULE, stop). + +-spec rfc1123() -> string(). +rfc1123() -> + case ets:lookup(?MODULE, rfc1123) of + [{rfc1123, Date}] -> + Date; + [] -> + "" + end. + +%% gen_server. + +-spec init([]) -> {ok, #state{}}. +init([]) -> + ?MODULE = ets:new(?MODULE, [named_table, protected, {read_concurrency, true}]), + handle_info(update_date, #state{}), + timer:send_interval(1000, update_date), + {ok, #state{}}. + +-type from() :: {pid(), term()}. +-spec handle_call + (stop, from(), State) -> {stop, normal, stopped, State} + when State::#state{}. +handle_call(stop, _From, State) -> + {stop, normal, stopped, State}; +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +-spec handle_cast(_, State) -> {noreply, State} when State::#state{}. +handle_cast(_Msg, State) -> + {noreply, State}. + +-spec handle_info(any(), State) -> {noreply, State} when State::#state{}. +handle_info(update_date, State) -> + Date = httpd_util:rfc1123_date(), + ets:insert(?MODULE, {rfc1123, Date}), + {noreply, State}; +handle_info(_Info, State) -> + {noreply, State}. + +-spec terminate(_, _) -> ok. +terminate(_Reason, _State) -> + ok. + +-spec code_change(_, State, _) -> {ok, State} when State::#state{}. +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + diff --git a/deps/mochiweb/src/mochiweb_cookies.erl b/deps/mochiweb/src/mochiweb_cookies.erl new file mode 100644 index 0000000..9539041 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_cookies.erl @@ -0,0 +1,349 @@ +%% @author Emad El-Haraty +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc HTTP Cookie parsing and generating (RFC 2109, RFC 2965). + +-module(mochiweb_cookies). +-export([parse_cookie/1, cookie/3, cookie/2]). + +-define(QUOTE, $\"). + +-define(IS_WHITESPACE(C), + (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)). + +%% RFC 2616 separators (called tspecials in RFC 2068) +-define(IS_SEPARATOR(C), + (C < 32 orelse + C =:= $\s orelse C =:= $\t orelse + C =:= $( orelse C =:= $) orelse C =:= $< orelse C =:= $> orelse + C =:= $@ orelse C =:= $, orelse C =:= $; orelse C =:= $: orelse + C =:= $\\ orelse C =:= $\" orelse C =:= $/ orelse + C =:= $[ orelse C =:= $] orelse C =:= $? orelse C =:= $= orelse + C =:= ${ orelse C =:= $})). + +%% @type proplist() = [{Key::string(), Value::string()}]. +%% @type header() = {Name::string(), Value::string()}. +%% @type int_seconds() = integer(). + +%% @spec cookie(Key::string(), Value::string()) -> header() +%% @doc Short-hand for cookie(Key, Value, []). +cookie(Key, Value) -> + cookie(Key, Value, []). + +%% @spec cookie(Key::string(), Value::string(), Options::[Option]) -> header() +%% where Option = {max_age, int_seconds()} | {local_time, {date(), time()}} +%% | {domain, string()} | {path, string()} +%% | {secure, true | false} | {http_only, true | false} +%% +%% @doc Generate a Set-Cookie header field tuple. +cookie(Key, Value, Options) -> + Cookie = [any_to_list(Key), "=", quote(Value), "; Version=1"], + %% Set-Cookie: + %% Comment, Domain, Max-Age, Path, Secure, Version + %% Set-Cookie2: + %% Comment, CommentURL, Discard, Domain, Max-Age, Path, Port, Secure, + %% Version + ExpiresPart = + case proplists:get_value(max_age, Options) of + undefined -> + ""; + RawAge -> + When = case proplists:get_value(local_time, Options) of + undefined -> + calendar:local_time(); + LocalTime -> + LocalTime + end, + Age = case RawAge < 0 of + true -> + 0; + false -> + RawAge + end, + ["; Expires=", age_to_cookie_date(Age, When), + "; Max-Age=", quote(Age)] + end, + SecurePart = + case proplists:get_value(secure, Options) of + true -> + "; Secure"; + _ -> + "" + end, + DomainPart = + case proplists:get_value(domain, Options) of + undefined -> + ""; + Domain -> + ["; Domain=", quote(Domain)] + end, + PathPart = + case proplists:get_value(path, Options) of + undefined -> + ""; + Path -> + ["; Path=", quote(Path)] + end, + HttpOnlyPart = + case proplists:get_value(http_only, Options) of + true -> + "; HttpOnly"; + _ -> + "" + end, + CookieParts = [Cookie, ExpiresPart, SecurePart, DomainPart, PathPart, HttpOnlyPart], + {"Set-Cookie", lists:flatten(CookieParts)}. + + +%% Every major browser incorrectly handles quoted strings in a +%% different and (worse) incompatible manner. Instead of wasting time +%% writing redundant code for each browser, we restrict cookies to +%% only contain characters that browsers handle compatibly. +%% +%% By replacing the definition of quote with this, we generate +%% RFC-compliant cookies: +%% +%% quote(V) -> +%% Fun = fun(?QUOTE, Acc) -> [$\\, ?QUOTE | Acc]; +%% (Ch, Acc) -> [Ch | Acc] +%% end, +%% [?QUOTE | lists:foldr(Fun, [?QUOTE], V)]. + +%% Convert to a string and raise an error if quoting is required. +quote(V0) -> + V = any_to_list(V0), + lists:all(fun(Ch) -> Ch =:= $/ orelse not ?IS_SEPARATOR(Ch) end, V) + orelse erlang:error({cookie_quoting_required, V}), + V. + + +%% Return a date in the form of: Wdy, DD-Mon-YYYY HH:MM:SS GMT +%% See also: rfc2109: 10.1.2 +rfc2109_cookie_expires_date(LocalTime) -> + {{YYYY,MM,DD},{Hour,Min,Sec}} = + case calendar:local_time_to_universal_time_dst(LocalTime) of + [] -> + {Date, {Hour1, Min1, Sec1}} = LocalTime, + LocalTime2 = {Date, {Hour1 + 1, Min1, Sec1}}, + case calendar:local_time_to_universal_time_dst(LocalTime2) of + [Gmt] -> Gmt; + [_,Gmt] -> Gmt + end; + [Gmt] -> Gmt; + [_,Gmt] -> Gmt + end, + DayNumber = calendar:day_of_the_week({YYYY,MM,DD}), + lists:flatten( + io_lib:format("~s, ~2.2.0w-~3.s-~4.4.0w ~2.2.0w:~2.2.0w:~2.2.0w GMT", + [httpd_util:day(DayNumber),DD,httpd_util:month(MM),YYYY,Hour,Min,Sec])). + +add_seconds(Secs, LocalTime) -> + Greg = calendar:datetime_to_gregorian_seconds(LocalTime), + calendar:gregorian_seconds_to_datetime(Greg + Secs). + +age_to_cookie_date(Age, LocalTime) -> + rfc2109_cookie_expires_date(add_seconds(Age, LocalTime)). + +%% @spec parse_cookie(string()) -> [{K::string(), V::string()}] +%% @doc Parse the contents of a Cookie header field, ignoring cookie +%% attributes, and return a simple property list. +parse_cookie("") -> + []; +parse_cookie(Cookie) -> + parse_cookie(Cookie, []). + +%% Internal API + +parse_cookie([], Acc) -> + lists:reverse(Acc); +parse_cookie(String, Acc) -> + {{Token, Value}, Rest} = read_pair(String), + Acc1 = case Token of + "" -> + Acc; + "$" ++ _ -> + Acc; + _ -> + [{Token, Value} | Acc] + end, + parse_cookie(Rest, Acc1). + +read_pair(String) -> + {Token, Rest} = read_token(skip_whitespace(String)), + {Value, Rest1} = read_value(skip_whitespace(Rest)), + {{Token, Value}, skip_past_separator(Rest1)}. + +read_value([$= | Value]) -> + Value1 = skip_whitespace(Value), + case Value1 of + [?QUOTE | _] -> + read_quoted(Value1); + _ -> + read_token(Value1) + end; +read_value(String) -> + {"", String}. + +read_quoted([?QUOTE | String]) -> + read_quoted(String, []). + +read_quoted([], Acc) -> + {lists:reverse(Acc), []}; +read_quoted([?QUOTE | Rest], Acc) -> + {lists:reverse(Acc), Rest}; +read_quoted([$\\, Any | Rest], Acc) -> + read_quoted(Rest, [Any | Acc]); +read_quoted([C | Rest], Acc) -> + read_quoted(Rest, [C | Acc]). + +skip_whitespace(String) -> + F = fun (C) -> ?IS_WHITESPACE(C) end, + lists:dropwhile(F, String). + +read_token(String) -> + F = fun (C) -> not ?IS_SEPARATOR(C) end, + lists:splitwith(F, String). + +skip_past_separator([]) -> + []; +skip_past_separator([$; | Rest]) -> + Rest; +skip_past_separator([$, | Rest]) -> + Rest; +skip_past_separator([_ | Rest]) -> + skip_past_separator(Rest). + +any_to_list(V) when is_list(V) -> + V; +any_to_list(V) when is_atom(V) -> + atom_to_list(V); +any_to_list(V) when is_binary(V) -> + binary_to_list(V); +any_to_list(V) when is_integer(V) -> + integer_to_list(V). + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +quote_test() -> + %% ?assertError eunit macro is not compatible with coverage module + try quote(":wq") + catch error:{cookie_quoting_required, ":wq"} -> ok + end, + ?assertEqual( + "foo", + quote(foo)), + ok. + +parse_cookie_test() -> + %% RFC example + C1 = "$Version=\"1\"; Customer=\"WILE_E_COYOTE\"; $Path=\"/acme\"; + Part_Number=\"Rocket_Launcher_0001\"; $Path=\"/acme\"; + Shipping=\"FedEx\"; $Path=\"/acme\"", + ?assertEqual( + [{"Customer","WILE_E_COYOTE"}, + {"Part_Number","Rocket_Launcher_0001"}, + {"Shipping","FedEx"}], + parse_cookie(C1)), + %% Potential edge cases + ?assertEqual( + [{"foo", "x"}], + parse_cookie("foo=\"\\x\"")), + ?assertEqual( + [], + parse_cookie("=")), + ?assertEqual( + [{"foo", ""}, {"bar", ""}], + parse_cookie(" foo ; bar ")), + ?assertEqual( + [{"foo", ""}, {"bar", ""}], + parse_cookie("foo=;bar=")), + ?assertEqual( + [{"foo", "\";"}, {"bar", ""}], + parse_cookie("foo = \"\\\";\";bar ")), + ?assertEqual( + [{"foo", "\";bar"}], + parse_cookie("foo=\"\\\";bar")), + ?assertEqual( + [], + parse_cookie([])), + ?assertEqual( + [{"foo", "bar"}, {"baz", "wibble"}], + parse_cookie("foo=bar , baz=wibble ")), + ok. + +domain_test() -> + ?assertEqual( + {"Set-Cookie", + "Customer=WILE_E_COYOTE; " + "Version=1; " + "Domain=acme.com; " + "HttpOnly"}, + cookie("Customer", "WILE_E_COYOTE", + [{http_only, true}, {domain, "acme.com"}])), + ok. + +local_time_test() -> + {"Set-Cookie", S} = cookie("Customer", "WILE_E_COYOTE", + [{max_age, 111}, {secure, true}]), + ?assertMatch( + ["Customer=WILE_E_COYOTE", + " Version=1", + " Expires=" ++ _, + " Max-Age=111", + " Secure"], + string:tokens(S, ";")), + ok. + +cookie_test() -> + C1 = {"Set-Cookie", + "Customer=WILE_E_COYOTE; " + "Version=1; " + "Path=/acme"}, + C1 = cookie("Customer", "WILE_E_COYOTE", [{path, "/acme"}]), + C1 = cookie("Customer", "WILE_E_COYOTE", + [{path, "/acme"}, {badoption, "negatory"}]), + C1 = cookie('Customer', 'WILE_E_COYOTE', [{path, '/acme'}]), + C1 = cookie(<<"Customer">>, <<"WILE_E_COYOTE">>, [{path, <<"/acme">>}]), + + {"Set-Cookie","=NoKey; Version=1"} = cookie("", "NoKey", []), + {"Set-Cookie","=NoKey; Version=1"} = cookie("", "NoKey"), + LocalTime = calendar:universal_time_to_local_time({{2007, 5, 15}, {13, 45, 33}}), + C2 = {"Set-Cookie", + "Customer=WILE_E_COYOTE; " + "Version=1; " + "Expires=Tue, 15-May-2007 13:45:33 GMT; " + "Max-Age=0"}, + C2 = cookie("Customer", "WILE_E_COYOTE", + [{max_age, -111}, {local_time, LocalTime}]), + C3 = {"Set-Cookie", + "Customer=WILE_E_COYOTE; " + "Version=1; " + "Expires=Wed, 16-May-2007 13:45:50 GMT; " + "Max-Age=86417"}, + C3 = cookie("Customer", "WILE_E_COYOTE", + [{max_age, 86417}, {local_time, LocalTime}]), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiweb_cover.erl b/deps/mochiweb/src/mochiweb_cover.erl new file mode 100644 index 0000000..ebc2c18 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_cover.erl @@ -0,0 +1,93 @@ +%% @author Bob Ippolito +%% @copyright 2010 Mochi Media, Inc. +%% +%% 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. + +%% @doc Workarounds for various cover deficiencies. +-module(mochiweb_cover). +-export([get_beam/1, get_abstract_code/1, + get_clauses/2, clause_lookup_table/1]). +-export([clause_lookup_table/2]). + +%% Internal + +get_beam(Module) -> + {Module, Beam, _Path} = code:get_object_code(Module), + Beam. + +get_abstract_code(Beam) -> + {ok, {_Module, + [{abstract_code, + {raw_abstract_v1, L}}]}} = beam_lib:chunks(Beam, [abstract_code]), + L. + +get_clauses(Function, Code) -> + [L] = [Clauses || {function, _, FName, _, Clauses} + <- Code, FName =:= Function], + L. + +clause_lookup_table(Module, Function) -> + clause_lookup_table( + get_clauses(Function, + get_abstract_code(get_beam(Module)))). + +clause_lookup_table(Clauses) -> + lists:foldr(fun clause_fold/2, [], Clauses). + +clause_fold({clause, _, + [InTerm], + _Guards=[], + [OutTerm]}, + Acc) -> + try [{erl_parse:normalise(InTerm), erl_parse:normalise(OutTerm)} | Acc] + catch error:_ -> Acc + end; +clause_fold(_, Acc) -> + Acc. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +foo_table(a) -> b; +foo_table("a") -> <<"b">>; +foo_table(123) -> {4, 3, 2}; +foo_table([list]) -> []; +foo_table([list1, list2]) -> [list1, list2, list3]; +foo_table(ignored) -> some, code, ignored; +foo_table(Var) -> Var. + +foo_table_test() -> + T = clause_lookup_table(?MODULE, foo_table), + [?assertEqual(V, foo_table(K)) || {K, V} <- T]. + +clause_lookup_table_test() -> + ?assertEqual(b, foo_table(a)), + ?assertEqual(ignored, foo_table(ignored)), + ?assertEqual('Var', foo_table('Var')), + ?assertEqual( + [{a, b}, + {"a", <<"b">>}, + {123, {4, 3, 2}}, + {[list], []}, + {[list1, list2], [list1, list2, list3]}], + clause_lookup_table(?MODULE, foo_table)). + +-endif. diff --git a/deps/mochiweb/src/mochiweb_echo.erl b/deps/mochiweb/src/mochiweb_echo.erl new file mode 100644 index 0000000..b14505c --- /dev/null +++ b/deps/mochiweb/src/mochiweb_echo.erl @@ -0,0 +1,59 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Simple and stupid echo server to demo mochiweb_socket_server. + +-module(mochiweb_echo). +-author('bob@mochimedia.com'). +-export([start/0, stop/0, loop/1]). + +stop() -> + mochiweb_socket_server:stop(?MODULE). + +start() -> + mochiweb_socket_server:start([{link, false} | options()]). + +options() -> + [{name, ?MODULE}, + {port, 6789}, + {ip, "127.0.0.1"}, + {max, 1}, + {loop, {?MODULE, loop}}]. + +loop(Socket) -> + case mochiweb_socket:recv(Socket, 0, 30000) of + {ok, Data} -> + case mochiweb_socket:send(Socket, Data) of + ok -> + loop(Socket); + _ -> + exit(normal) + end; + _Other -> + exit(normal) + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochiweb_headers.erl b/deps/mochiweb/src/mochiweb_headers.erl new file mode 100644 index 0000000..457758f --- /dev/null +++ b/deps/mochiweb/src/mochiweb_headers.erl @@ -0,0 +1,438 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Case preserving (but case insensitive) HTTP Header dictionary. + +-module(mochiweb_headers). +-author('bob@mochimedia.com'). +-export([empty/0, from_list/1, insert/3, enter/3, get_value/2, lookup/2]). +-export([delete_any/2, get_primary_value/2, get_combined_value/2]). +-export([default/3, enter_from_list/2, default_from_list/2]). +-export([to_list/1, make/1]). +-export([from_binary/1]). + +%% @type headers(). +%% @type key() = atom() | binary() | string(). +%% @type value() = atom() | binary() | string() | integer(). + +%% @spec empty() -> headers() +%% @doc Create an empty headers structure. +empty() -> + gb_trees:empty(). + +%% @spec make(headers() | [{key(), value()}]) -> headers() +%% @doc Construct a headers() from the given list. +make(L) when is_list(L) -> + from_list(L); +%% assume a non-list is already mochiweb_headers. +make(T) -> + T. + +%% @spec from_binary(iolist()) -> headers() +%% @doc Transforms a raw HTTP header into a mochiweb headers structure. +%% +%% The given raw HTTP header can be one of the following: +%% +%% 1) A string or a binary representing a full HTTP header ending with +%% double CRLF. +%% Examples: +%% ``` +%% "Content-Length: 47\r\nContent-Type: text/plain\r\n\r\n" +%% <<"Content-Length: 47\r\nContent-Type: text/plain\r\n\r\n">>''' +%% +%% 2) A list of binaries or strings where each element represents a raw +%% HTTP header line ending with a single CRLF. +%% Examples: +%% ``` +%% [<<"Content-Length: 47\r\n">>, <<"Content-Type: text/plain\r\n">>] +%% ["Content-Length: 47\r\n", "Content-Type: text/plain\r\n"] +%% ["Content-Length: 47\r\n", <<"Content-Type: text/plain\r\n">>]''' +%% +from_binary(RawHttpHeader) when is_binary(RawHttpHeader) -> + from_binary(RawHttpHeader, []); +from_binary(RawHttpHeaderList) -> + from_binary(list_to_binary([RawHttpHeaderList, "\r\n"])). + +from_binary(RawHttpHeader, Acc) -> + case erlang:decode_packet(httph, RawHttpHeader, []) of + {ok, {http_header, _, H, _, V}, Rest} -> + from_binary(Rest, [{H, V} | Acc]); + _ -> + make(Acc) + end. + +%% @spec from_list([{key(), value()}]) -> headers() +%% @doc Construct a headers() from the given list. +from_list(List) -> + lists:foldl(fun ({K, V}, T) -> insert(K, V, T) end, empty(), List). + +%% @spec enter_from_list([{key(), value()}], headers()) -> headers() +%% @doc Insert pairs into the headers, replace any values for existing keys. +enter_from_list(List, T) -> + lists:foldl(fun ({K, V}, T1) -> enter(K, V, T1) end, T, List). + +%% @spec default_from_list([{key(), value()}], headers()) -> headers() +%% @doc Insert pairs into the headers for keys that do not already exist. +default_from_list(List, T) -> + lists:foldl(fun ({K, V}, T1) -> default(K, V, T1) end, T, List). + +%% @spec to_list(headers()) -> [{key(), string()}] +%% @doc Return the contents of the headers. The keys will be the exact key +%% that was first inserted (e.g. may be an atom or binary, case is +%% preserved). +to_list(T) -> + F = fun ({K, {array, L}}, Acc) -> + L1 = lists:reverse(L), + lists:foldl(fun (V, Acc1) -> [{K, V} | Acc1] end, Acc, L1); + (Pair, Acc) -> + [Pair | Acc] + end, + lists:reverse(lists:foldl(F, [], gb_trees:values(T))). + +%% @spec get_value(key(), headers()) -> string() | undefined +%% @doc Return the value of the given header using a case insensitive search. +%% undefined will be returned for keys that are not present. +get_value(K, T) -> + case lookup(K, T) of + {value, {_, V}} -> + expand(V); + none -> + undefined + end. + +%% @spec get_primary_value(key(), headers()) -> string() | undefined +%% @doc Return the value of the given header up to the first semicolon using +%% a case insensitive search. undefined will be returned for keys +%% that are not present. +get_primary_value(K, T) -> + case get_value(K, T) of + undefined -> + undefined; + V -> + lists:takewhile(fun (C) -> C =/= $; end, V) + end. + +%% @spec get_combined_value(key(), headers()) -> string() | undefined +%% @doc Return the value from the given header using a case insensitive search. +%% If the value of the header is a comma-separated list where holds values +%% are all identical, the identical value will be returned. +%% undefined will be returned for keys that are not present or the +%% values in the list are not the same. +%% +%% NOTE: The process isn't designed for a general purpose. If you need +%% to access all values in the combined header, please refer to +%% '''tokenize_header_value/1'''. +%% +%% Section 4.2 of the RFC 2616 (HTTP 1.1) describes multiple message-header +%% fields with the same field-name may be present in a message if and only +%% if the entire field-value for that header field is defined as a +%% comma-separated list [i.e., #(values)]. +get_combined_value(K, T) -> + case get_value(K, T) of + undefined -> + undefined; + V -> + case sets:to_list(sets:from_list(tokenize_header_value(V))) of + [Val] -> + Val; + _ -> + undefined + end + end. + +%% @spec lookup(key(), headers()) -> {value, {key(), string()}} | none +%% @doc Return the case preserved key and value for the given header using +%% a case insensitive search. none will be returned for keys that are +%% not present. +lookup(K, T) -> + case gb_trees:lookup(normalize(K), T) of + {value, {K0, V}} -> + {value, {K0, expand(V)}}; + none -> + none + end. + +%% @spec default(key(), value(), headers()) -> headers() +%% @doc Insert the pair into the headers if it does not already exist. +default(K, V, T) -> + K1 = normalize(K), + V1 = any_to_list(V), + try gb_trees:insert(K1, {K, V1}, T) + catch + error:{key_exists, _} -> + T + end. + +%% @spec enter(key(), value(), headers()) -> headers() +%% @doc Insert the pair into the headers, replacing any pre-existing key. +enter(K, V, T) -> + K1 = normalize(K), + V1 = any_to_list(V), + gb_trees:enter(K1, {K, V1}, T). + +%% @spec insert(key(), value(), headers()) -> headers() +%% @doc Insert the pair into the headers, merging with any pre-existing key. +%% A merge is done with Value = V0 ++ ", " ++ V1. +insert(K, V, T) -> + K1 = normalize(K), + V1 = any_to_list(V), + try gb_trees:insert(K1, {K, V1}, T) + catch + error:{key_exists, _} -> + {K0, V0} = gb_trees:get(K1, T), + V2 = merge(K1, V1, V0), + gb_trees:update(K1, {K0, V2}, T) + end. + +%% @spec delete_any(key(), headers()) -> headers() +%% @doc Delete the header corresponding to key if it is present. +delete_any(K, T) -> + K1 = normalize(K), + gb_trees:delete_any(K1, T). + +%% Internal API + +tokenize_header_value(undefined) -> + undefined; +tokenize_header_value(V) -> + reversed_tokens(trim_and_reverse(V, false), [], []). + +trim_and_reverse([S | Rest], Reversed) when S=:=$ ; S=:=$\n; S=:=$\t -> + trim_and_reverse(Rest, Reversed); +trim_and_reverse(V, false) -> + trim_and_reverse(lists:reverse(V), true); +trim_and_reverse(V, true) -> + V. + +reversed_tokens([], [], Acc) -> + Acc; +reversed_tokens([], Token, Acc) -> + [Token | Acc]; +reversed_tokens("\"" ++ Rest, [], Acc) -> + case extract_quoted_string(Rest, []) of + {String, NewRest} -> + reversed_tokens(NewRest, [], [String | Acc]); + undefined -> + undefined + end; +reversed_tokens("\"" ++ _Rest, _Token, _Acc) -> + undefined; +reversed_tokens([C | Rest], [], Acc) when C=:=$ ;C=:=$\n;C=:=$\t;C=:=$, -> + reversed_tokens(Rest, [], Acc); +reversed_tokens([C | Rest], Token, Acc) when C=:=$ ;C=:=$\n;C=:=$\t;C=:=$, -> + reversed_tokens(Rest, [], [Token | Acc]); +reversed_tokens([C | Rest], Token, Acc) -> + reversed_tokens(Rest, [C | Token], Acc); +reversed_tokens(_, _, _) -> + undefeined. + +extract_quoted_string([], _Acc) -> + undefined; +extract_quoted_string("\"\\" ++ Rest, Acc) -> + extract_quoted_string(Rest, "\"" ++ Acc); +extract_quoted_string("\"" ++ Rest, Acc) -> + {Acc, Rest}; +extract_quoted_string([C | Rest], Acc) -> + extract_quoted_string(Rest, [C | Acc]). + +expand({array, L}) -> + mochiweb_util:join(lists:reverse(L), ", "); +expand(V) -> + V. + +merge("set-cookie", V1, {array, L}) -> + {array, [V1 | L]}; +merge("set-cookie", V1, V0) -> + {array, [V1, V0]}; +merge(_, V1, V0) -> + V0 ++ ", " ++ V1. + +normalize(K) when is_list(K) -> + string:to_lower(K); +normalize(K) when is_atom(K) -> + normalize(atom_to_list(K)); +normalize(K) when is_binary(K) -> + normalize(binary_to_list(K)). + +any_to_list(V) when is_list(V) -> + V; +any_to_list(V) when is_atom(V) -> + atom_to_list(V); +any_to_list(V) when is_binary(V) -> + binary_to_list(V); +any_to_list(V) when is_integer(V) -> + integer_to_list(V). + +%% +%% Tests. +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +make_test() -> + Identity = make([{hdr, foo}]), + ?assertEqual( + Identity, + make(Identity)). + +enter_from_list_test() -> + H = make([{hdr, foo}]), + ?assertEqual( + [{baz, "wibble"}, {hdr, "foo"}], + to_list(enter_from_list([{baz, wibble}], H))), + ?assertEqual( + [{hdr, "bar"}], + to_list(enter_from_list([{hdr, bar}], H))), + ok. + +default_from_list_test() -> + H = make([{hdr, foo}]), + ?assertEqual( + [{baz, "wibble"}, {hdr, "foo"}], + to_list(default_from_list([{baz, wibble}], H))), + ?assertEqual( + [{hdr, "foo"}], + to_list(default_from_list([{hdr, bar}], H))), + ok. + +get_primary_value_test() -> + H = make([{hdr, foo}, {baz, <<"wibble;taco">>}]), + ?assertEqual( + "foo", + get_primary_value(hdr, H)), + ?assertEqual( + undefined, + get_primary_value(bar, H)), + ?assertEqual( + "wibble", + get_primary_value(<<"baz">>, H)), + ok. + +get_combined_value_test() -> + H = make([{hdr, foo}, {baz, <<"wibble,taco">>}, {content_length, "123, 123"}, + {test, " 123, 123, 123 , 123,123 "}, + {test2, "456, 123, 123 , 123"}, + {test3, "123"}, {test4, " 123, "}]), + ?assertEqual( + "foo", + get_combined_value(hdr, H)), + ?assertEqual( + undefined, + get_combined_value(bar, H)), + ?assertEqual( + undefined, + get_combined_value(<<"baz">>, H)), + ?assertEqual( + "123", + get_combined_value(<<"content_length">>, H)), + ?assertEqual( + "123", + get_combined_value(<<"test">>, H)), + ?assertEqual( + undefined, + get_combined_value(<<"test2">>, H)), + ?assertEqual( + "123", + get_combined_value(<<"test3">>, H)), + ?assertEqual( + "123", + get_combined_value(<<"test4">>, H)), + ok. + +set_cookie_test() -> + H = make([{"set-cookie", foo}, {"set-cookie", bar}, {"set-cookie", baz}]), + ?assertEqual( + [{"set-cookie", "foo"}, {"set-cookie", "bar"}, {"set-cookie", "baz"}], + to_list(H)), + ok. + +headers_test() -> + H = ?MODULE:make([{hdr, foo}, {"Hdr", "bar"}, {'Hdr', 2}]), + [{hdr, "foo, bar, 2"}] = ?MODULE:to_list(H), + H1 = ?MODULE:insert(taco, grande, H), + [{hdr, "foo, bar, 2"}, {taco, "grande"}] = ?MODULE:to_list(H1), + H2 = ?MODULE:make([{"Set-Cookie", "foo"}]), + [{"Set-Cookie", "foo"}] = ?MODULE:to_list(H2), + H3 = ?MODULE:insert("Set-Cookie", "bar", H2), + [{"Set-Cookie", "foo"}, {"Set-Cookie", "bar"}] = ?MODULE:to_list(H3), + "foo, bar" = ?MODULE:get_value("set-cookie", H3), + {value, {"Set-Cookie", "foo, bar"}} = ?MODULE:lookup("set-cookie", H3), + undefined = ?MODULE:get_value("shibby", H3), + none = ?MODULE:lookup("shibby", H3), + H4 = ?MODULE:insert("content-type", + "application/x-www-form-urlencoded; charset=utf8", + H3), + "application/x-www-form-urlencoded" = ?MODULE:get_primary_value( + "content-type", H4), + H4 = ?MODULE:delete_any("nonexistent-header", H4), + H3 = ?MODULE:delete_any("content-type", H4), + HB = <<"Content-Length: 47\r\nContent-Type: text/plain\r\n\r\n">>, + H_HB = ?MODULE:from_binary(HB), + H_HB = ?MODULE:from_binary(binary_to_list(HB)), + "47" = ?MODULE:get_value("Content-Length", H_HB), + "text/plain" = ?MODULE:get_value("Content-Type", H_HB), + L_H_HB = ?MODULE:to_list(H_HB), + 2 = length(L_H_HB), + true = lists:member({'Content-Length', "47"}, L_H_HB), + true = lists:member({'Content-Type', "text/plain"}, L_H_HB), + HL = [ <<"Content-Length: 47\r\n">>, <<"Content-Type: text/plain\r\n">> ], + HL2 = [ "Content-Length: 47\r\n", <<"Content-Type: text/plain\r\n">> ], + HL3 = [ <<"Content-Length: 47\r\n">>, "Content-Type: text/plain\r\n" ], + H_HL = ?MODULE:from_binary(HL), + H_HL = ?MODULE:from_binary(HL2), + H_HL = ?MODULE:from_binary(HL3), + "47" = ?MODULE:get_value("Content-Length", H_HL), + "text/plain" = ?MODULE:get_value("Content-Type", H_HL), + L_H_HL = ?MODULE:to_list(H_HL), + 2 = length(L_H_HL), + true = lists:member({'Content-Length', "47"}, L_H_HL), + true = lists:member({'Content-Type', "text/plain"}, L_H_HL), + [] = ?MODULE:to_list(?MODULE:from_binary(<<>>)), + [] = ?MODULE:to_list(?MODULE:from_binary(<<"">>)), + [] = ?MODULE:to_list(?MODULE:from_binary(<<"\r\n">>)), + [] = ?MODULE:to_list(?MODULE:from_binary(<<"\r\n\r\n">>)), + [] = ?MODULE:to_list(?MODULE:from_binary("")), + [] = ?MODULE:to_list(?MODULE:from_binary([<<>>])), + [] = ?MODULE:to_list(?MODULE:from_binary([<<"">>])), + [] = ?MODULE:to_list(?MODULE:from_binary([<<"\r\n">>])), + [] = ?MODULE:to_list(?MODULE:from_binary([<<"\r\n\r\n">>])), + ok. + +tokenize_header_value_test() -> + ?assertEqual(["a quote in a \"quote\"."], + tokenize_header_value("\"a quote in a \\\"quote\\\".\"")), + ?assertEqual(["abc"], tokenize_header_value("abc")), + ?assertEqual(["abc", "def"], tokenize_header_value("abc def")), + ?assertEqual(["abc", "def"], tokenize_header_value("abc , def")), + ?assertEqual(["abc", "def"], tokenize_header_value(",abc ,, def,,")), + ?assertEqual(["abc def"], tokenize_header_value("\"abc def\" ")), + ?assertEqual(["abc, def"], tokenize_header_value("\"abc, def\"")), + ?assertEqual(["\\a\\$"], tokenize_header_value("\"\\a\\$\"")), + ?assertEqual(["abc def", "foo, bar", "12345", ""], + tokenize_header_value("\"abc def\" \"foo, bar\" , 12345, \"\"")), + ?assertEqual(undefined, + tokenize_header_value(undefined)), + ?assertEqual(undefined, + tokenize_header_value("umatched quote\"")), + ?assertEqual(undefined, + tokenize_header_value("\"unmatched quote")). + +-endif. diff --git a/deps/mochiweb/src/mochiweb_html.erl b/deps/mochiweb/src/mochiweb_html.erl new file mode 100644 index 0000000..70723af --- /dev/null +++ b/deps/mochiweb/src/mochiweb_html.erl @@ -0,0 +1,815 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Loosely tokenizes and generates parse trees for HTML 4. +-module(mochiweb_html). +-export([tokens/1, parse/1, parse_tokens/1, to_tokens/1, escape/1, + escape_attr/1, to_html/1]). +-compile([export_all]). +-ifdef(TEST). +-export([destack/1, destack/2, is_singleton/1]). +-endif. + +%% This is a macro to placate syntax highlighters.. +-define(QUOTE, $\"). %% $\" +-define(SQUOTE, $\'). %% $\' +-define(ADV_COL(S, N), + S#decoder{column=N+S#decoder.column, + offset=N+S#decoder.offset}). +-define(INC_COL(S), + S#decoder{column=1+S#decoder.column, + offset=1+S#decoder.offset}). +-define(INC_LINE(S), + S#decoder{column=1, + line=1+S#decoder.line, + offset=1+S#decoder.offset}). +-define(INC_CHAR(S, C), + case C of + $\n -> + S#decoder{column=1, + line=1+S#decoder.line, + offset=1+S#decoder.offset}; + _ -> + S#decoder{column=1+S#decoder.column, + offset=1+S#decoder.offset} + end). + +-define(IS_WHITESPACE(C), + (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)). +-define(IS_LITERAL_SAFE(C), + ((C >= $A andalso C =< $Z) orelse (C >= $a andalso C =< $z) + orelse (C >= $0 andalso C =< $9))). +-define(PROBABLE_CLOSE(C), + (C =:= $> orelse ?IS_WHITESPACE(C))). + +-record(decoder, {line=1, + column=1, + offset=0}). + +%% @type html_node() = {string(), [html_attr()], [html_node() | string()]} +%% @type html_attr() = {string(), string()} +%% @type html_token() = html_data() | start_tag() | end_tag() | inline_html() | html_comment() | html_doctype() +%% @type html_data() = {data, string(), Whitespace::boolean()} +%% @type start_tag() = {start_tag, Name, [html_attr()], Singleton::boolean()} +%% @type end_tag() = {end_tag, Name} +%% @type html_comment() = {comment, Comment} +%% @type html_doctype() = {doctype, [Doctype]} +%% @type inline_html() = {'=', iolist()} + +%% External API. + +%% @spec parse(string() | binary()) -> html_node() +%% @doc tokenize and then transform the token stream into a HTML tree. +parse(Input) -> + parse_tokens(tokens(Input)). + +%% @spec parse_tokens([html_token()]) -> html_node() +%% @doc Transform the output of tokens(Doc) into a HTML tree. +parse_tokens(Tokens) when is_list(Tokens) -> + %% Skip over doctype, processing instructions + [{start_tag, Tag, Attrs, false} | Rest] = find_document(Tokens, normal), + {Tree, _} = tree(Rest, [norm({Tag, Attrs})]), + Tree. + +find_document(Tokens=[{start_tag, _Tag, _Attrs, false} | _Rest], Mode) -> + maybe_add_html_tag(Tokens, Mode); +find_document([{doctype, [<<"html">>]} | Rest], _Mode) -> + find_document(Rest, html5); +find_document([_T | Rest], Mode) -> + find_document(Rest, Mode); +find_document([], _Mode) -> + []. + +maybe_add_html_tag(Tokens=[{start_tag, Tag, _Attrs, false} | _], html5) + when Tag =/= <<"html">> -> + [{start_tag, <<"html">>, [], false} | Tokens]; +maybe_add_html_tag(Tokens, _Mode) -> + Tokens. + +%% @spec tokens(StringOrBinary) -> [html_token()] +%% @doc Transform the input UTF-8 HTML into a token stream. +tokens(Input) -> + tokens(iolist_to_binary(Input), #decoder{}, []). + +%% @spec to_tokens(html_node()) -> [html_token()] +%% @doc Convert a html_node() tree to a list of tokens. +to_tokens({Tag0}) -> + to_tokens({Tag0, [], []}); +to_tokens(T={'=', _}) -> + [T]; +to_tokens(T={doctype, _}) -> + [T]; +to_tokens(T={comment, _}) -> + [T]; +to_tokens({Tag0, Acc}) -> + %% This is only allowed in sub-tags: {p, [{"class", "foo"}]} + to_tokens({Tag0, [], Acc}); +to_tokens({Tag0, Attrs, Acc}) -> + Tag = to_tag(Tag0), + case is_singleton(Tag) of + true -> + to_tokens([], [{start_tag, Tag, Attrs, true}]); + false -> + to_tokens([{Tag, Acc}], [{start_tag, Tag, Attrs, false}]) + end. + +%% @spec to_html([html_token()] | html_node()) -> iolist() +%% @doc Convert a list of html_token() to a HTML document. +to_html(Node) when is_tuple(Node) -> + to_html(to_tokens(Node)); +to_html(Tokens) when is_list(Tokens) -> + to_html(Tokens, []). + +%% @spec escape(string() | atom() | binary()) -> binary() +%% @doc Escape a string such that it's safe for HTML (amp; lt; gt;). +escape(B) when is_binary(B) -> + escape(binary_to_list(B), []); +escape(A) when is_atom(A) -> + escape(atom_to_list(A), []); +escape(S) when is_list(S) -> + escape(S, []). + +%% @spec escape_attr(string() | binary() | atom() | integer() | float()) -> binary() +%% @doc Escape a string such that it's safe for HTML attrs +%% (amp; lt; gt; quot;). +escape_attr(B) when is_binary(B) -> + escape_attr(binary_to_list(B), []); +escape_attr(A) when is_atom(A) -> + escape_attr(atom_to_list(A), []); +escape_attr(S) when is_list(S) -> + escape_attr(S, []); +escape_attr(I) when is_integer(I) -> + escape_attr(integer_to_list(I), []); +escape_attr(F) when is_float(F) -> + escape_attr(mochinum:digits(F), []). + +to_html([], Acc) -> + lists:reverse(Acc); +to_html([{'=', Content} | Rest], Acc) -> + to_html(Rest, [Content | Acc]); +to_html([{pi, Bin} | Rest], Acc) -> + Open = [<<">, + Bin, + <<"?>">>], + to_html(Rest, [Open | Acc]); +to_html([{pi, Tag, Attrs} | Rest], Acc) -> + Open = [<<">, + Tag, + attrs_to_html(Attrs, []), + <<"?>">>], + to_html(Rest, [Open | Acc]); +to_html([{comment, Comment} | Rest], Acc) -> + to_html(Rest, [[<<"">>] | Acc]); +to_html([{doctype, Parts} | Rest], Acc) -> + Inside = doctype_to_html(Parts, Acc), + to_html(Rest, [[<<">, Inside, <<">">>] | Acc]); +to_html([{data, Data, _Whitespace} | Rest], Acc) -> + to_html(Rest, [escape(Data) | Acc]); +to_html([{start_tag, Tag, Attrs, Singleton} | Rest], Acc) -> + Open = [<<"<">>, + Tag, + attrs_to_html(Attrs, []), + case Singleton of + true -> <<" />">>; + false -> <<">">> + end], + to_html(Rest, [Open | Acc]); +to_html([{end_tag, Tag} | Rest], Acc) -> + to_html(Rest, [[<<">, Tag, <<">">>] | Acc]). + +doctype_to_html([], Acc) -> + lists:reverse(Acc); +doctype_to_html([Word | Rest], Acc) -> + case lists:all(fun (C) -> ?IS_LITERAL_SAFE(C) end, + binary_to_list(iolist_to_binary(Word))) of + true -> + doctype_to_html(Rest, [[<<" ">>, Word] | Acc]); + false -> + doctype_to_html(Rest, [[<<" \"">>, escape_attr(Word), ?QUOTE] | Acc]) + end. + +attrs_to_html([], Acc) -> + lists:reverse(Acc); +attrs_to_html([{K, V} | Rest], Acc) -> + attrs_to_html(Rest, + [[<<" ">>, escape(K), <<"=\"">>, + escape_attr(V), <<"\"">>] | Acc]). + +escape([], Acc) -> + list_to_binary(lists:reverse(Acc)); +escape("<" ++ Rest, Acc) -> + escape(Rest, lists:reverse("<", Acc)); +escape(">" ++ Rest, Acc) -> + escape(Rest, lists:reverse(">", Acc)); +escape("&" ++ Rest, Acc) -> + escape(Rest, lists:reverse("&", Acc)); +escape([C | Rest], Acc) -> + escape(Rest, [C | Acc]). + +escape_attr([], Acc) -> + list_to_binary(lists:reverse(Acc)); +escape_attr("<" ++ Rest, Acc) -> + escape_attr(Rest, lists:reverse("<", Acc)); +escape_attr(">" ++ Rest, Acc) -> + escape_attr(Rest, lists:reverse(">", Acc)); +escape_attr("&" ++ Rest, Acc) -> + escape_attr(Rest, lists:reverse("&", Acc)); +escape_attr([?QUOTE | Rest], Acc) -> + escape_attr(Rest, lists:reverse(""", Acc)); +escape_attr([C | Rest], Acc) -> + escape_attr(Rest, [C | Acc]). + +to_tag(A) when is_atom(A) -> + norm(atom_to_list(A)); +to_tag(L) -> + norm(L). + +to_tokens([], Acc) -> + lists:reverse(Acc); +to_tokens([{Tag, []} | Rest], Acc) -> + to_tokens(Rest, [{end_tag, to_tag(Tag)} | Acc]); +to_tokens([{Tag0, [{T0} | R1]} | Rest], Acc) -> + %% Allow {br} + to_tokens([{Tag0, [{T0, [], []} | R1]} | Rest], Acc); +to_tokens([{Tag0, [T0={'=', _C0} | R1]} | Rest], Acc) -> + %% Allow {'=', iolist()} + to_tokens([{Tag0, R1} | Rest], [T0 | Acc]); +to_tokens([{Tag0, [T0={comment, _C0} | R1]} | Rest], Acc) -> + %% Allow {comment, iolist()} + to_tokens([{Tag0, R1} | Rest], [T0 | Acc]); +to_tokens([{Tag0, [T0={pi, _S0} | R1]} | Rest], Acc) -> + %% Allow {pi, binary()} + to_tokens([{Tag0, R1} | Rest], [T0 | Acc]); +to_tokens([{Tag0, [T0={pi, _S0, _A0} | R1]} | Rest], Acc) -> + %% Allow {pi, binary(), list()} + to_tokens([{Tag0, R1} | Rest], [T0 | Acc]); +to_tokens([{Tag0, [{T0, A0=[{_, _} | _]} | R1]} | Rest], Acc) -> + %% Allow {p, [{"class", "foo"}]} + to_tokens([{Tag0, [{T0, A0, []} | R1]} | Rest], Acc); +to_tokens([{Tag0, [{T0, C0} | R1]} | Rest], Acc) -> + %% Allow {p, "content"} and {p, <<"content">>} + to_tokens([{Tag0, [{T0, [], C0} | R1]} | Rest], Acc); +to_tokens([{Tag0, [{T0, A1, C0} | R1]} | Rest], Acc) when is_binary(C0) -> + %% Allow {"p", [{"class", "foo"}], <<"content">>} + to_tokens([{Tag0, [{T0, A1, binary_to_list(C0)} | R1]} | Rest], Acc); +to_tokens([{Tag0, [{T0, A1, C0=[C | _]} | R1]} | Rest], Acc) + when is_integer(C) -> + %% Allow {"p", [{"class", "foo"}], "content"} + to_tokens([{Tag0, [{T0, A1, [C0]} | R1]} | Rest], Acc); +to_tokens([{Tag0, [{T0, A1, C1} | R1]} | Rest], Acc) -> + %% Native {"p", [{"class", "foo"}], ["content"]} + Tag = to_tag(Tag0), + T1 = to_tag(T0), + case is_singleton(norm(T1)) of + true -> + to_tokens([{Tag, R1} | Rest], [{start_tag, T1, A1, true} | Acc]); + false -> + to_tokens([{T1, C1}, {Tag, R1} | Rest], + [{start_tag, T1, A1, false} | Acc]) + end; +to_tokens([{Tag0, [L | R1]} | Rest], Acc) when is_list(L) -> + %% List text + Tag = to_tag(Tag0), + to_tokens([{Tag, R1} | Rest], [{data, iolist_to_binary(L), false} | Acc]); +to_tokens([{Tag0, [B | R1]} | Rest], Acc) when is_binary(B) -> + %% Binary text + Tag = to_tag(Tag0), + to_tokens([{Tag, R1} | Rest], [{data, B, false} | Acc]). + +tokens(B, S=#decoder{offset=O}, Acc) -> + case B of + <<_:O/binary>> -> + lists:reverse(Acc); + _ -> + {Tag, S1} = tokenize(B, S), + case parse_flag(Tag) of + script -> + {Tag2, S2} = tokenize_script(B, S1), + tokens(B, S2, [Tag2, Tag | Acc]); + textarea -> + {Tag2, S2} = tokenize_textarea(B, S1), + tokens(B, S2, [Tag2, Tag | Acc]); + none -> + tokens(B, S1, [Tag | Acc]) + end + end. + +parse_flag({start_tag, B, _, false}) -> + case string:to_lower(binary_to_list(B)) of + "script" -> + script; + "textarea" -> + textarea; + _ -> + none + end; +parse_flag(_) -> + none. + +tokenize(B, S=#decoder{offset=O}) -> + case B of + <<_:O/binary, "", _/binary>> -> + Len = O - Start, + <<_:Start/binary, Raw:Len/binary, _/binary>> = Bin, + {{comment, Raw}, ?ADV_COL(S, 3)}; + <<_:O/binary, C, _/binary>> -> + tokenize_comment(Bin, ?INC_CHAR(S, C), Start); + <<_:Start/binary, Raw/binary>> -> + {{comment, Raw}, S} + end. + +tokenize_script(Bin, S=#decoder{offset=O}) -> + tokenize_script(Bin, S, O). + +tokenize_script(Bin, S=#decoder{offset=O}, Start) -> + case Bin of + %% Just a look-ahead, we want the end_tag separately + <<_:O/binary, $<, $/, SS, CC, RR, II, PP, TT, ZZ, _/binary>> + when (SS =:= $s orelse SS =:= $S) andalso + (CC =:= $c orelse CC =:= $C) andalso + (RR =:= $r orelse RR =:= $R) andalso + (II =:= $i orelse II =:= $I) andalso + (PP =:= $p orelse PP =:= $P) andalso + (TT=:= $t orelse TT =:= $T) andalso + ?PROBABLE_CLOSE(ZZ) -> + Len = O - Start, + <<_:Start/binary, Raw:Len/binary, _/binary>> = Bin, + {{data, Raw, false}, S}; + <<_:O/binary, C, _/binary>> -> + tokenize_script(Bin, ?INC_CHAR(S, C), Start); + <<_:Start/binary, Raw/binary>> -> + {{data, Raw, false}, S} + end. + +tokenize_textarea(Bin, S=#decoder{offset=O}) -> + tokenize_textarea(Bin, S, O). + +tokenize_textarea(Bin, S=#decoder{offset=O}, Start) -> + case Bin of + %% Just a look-ahead, we want the end_tag separately + <<_:O/binary, $<, $/, TT, EE, XX, TT2, AA, RR, EE2, AA2, ZZ, _/binary>> + when (TT =:= $t orelse TT =:= $T) andalso + (EE =:= $e orelse EE =:= $E) andalso + (XX =:= $x orelse XX =:= $X) andalso + (TT2 =:= $t orelse TT2 =:= $T) andalso + (AA =:= $a orelse AA =:= $A) andalso + (RR =:= $r orelse RR =:= $R) andalso + (EE2 =:= $e orelse EE2 =:= $E) andalso + (AA2 =:= $a orelse AA2 =:= $A) andalso + ?PROBABLE_CLOSE(ZZ) -> + Len = O - Start, + <<_:Start/binary, Raw:Len/binary, _/binary>> = Bin, + {{data, Raw, false}, S}; + <<_:O/binary, C, _/binary>> -> + tokenize_textarea(Bin, ?INC_CHAR(S, C), Start); + <<_:Start/binary, Raw/binary>> -> + {{data, Raw, false}, S} + end. diff --git a/deps/mochiweb/src/mochiweb_http.erl b/deps/mochiweb/src/mochiweb_http.erl new file mode 100644 index 0000000..568019f --- /dev/null +++ b/deps/mochiweb/src/mochiweb_http.erl @@ -0,0 +1,307 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc HTTP server. + +-module(mochiweb_http). +-author('bob@mochimedia.com'). +-export([start/1, start_link/1, stop/0, stop/1]). +-export([loop/3]). +-export([after_response/2, reentry/1]). +-export([parse_range_request/1, range_skip_length/2]). + +-define(REQUEST_RECV_TIMEOUT, 300000). %% timeout waiting for request line +-define(HEADERS_RECV_TIMEOUT, 30000). %% timeout waiting for headers + +-define(MAX_HEADERS, 1000). +-define(DEFAULTS, [{name, ?MODULE}, + {port, 8888}]). + +-ifdef(gen_tcp_r15b_workaround). +r15b_workaround() -> true. +-else. +r15b_workaround() -> false. +-endif. + +parse_options(Options) -> + {loop, HttpLoop} = proplists:lookup(loop, Options), + Loop = {?MODULE, loop, [HttpLoop]}, + Options1 = [{loop, Loop} | proplists:delete(loop, Options)], + mochilists:set_defaults(?DEFAULTS, Options1). + +stop() -> + mochiweb_socket_server:stop(?MODULE). + +stop(Name) -> + mochiweb_socket_server:stop(Name). + +%% @spec start(Options) -> ServerRet +%% Options = [option()] +%% Option = {name, atom()} | {ip, string() | tuple()} | {backlog, integer()} +%% | {nodelay, boolean()} | {acceptor_pool_size, integer()} +%% | {ssl, boolean()} | {profile_fun, undefined | (Props) -> ok} +%% | {link, false} | {recbuf, undefined | non_negative_integer()} +%% @doc Start a mochiweb server. +%% profile_fun is used to profile accept timing. +%% After each accept, if defined, profile_fun is called with a proplist of a subset of the mochiweb_socket_server state and timing information. +%% The proplist is as follows: [{name, Name}, {port, Port}, {active_sockets, ActiveSockets}, {timing, Timing}]. +%% @end +start(Options) -> + ok = ensure_started(mochiweb_clock), + mochiweb_socket_server:start(parse_options(Options)). + +start_link(Options) -> + ok = ensure_started(mochiweb_clock), + mochiweb_socket_server:start_link(parse_options(Options)). + +ensure_started(M) -> + case M:start() of + {ok, _Pid} -> + ok; + {error, {already_started, _Pid}} -> + ok + end. + +loop(Socket, Opts, Body) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, http}])), + request(Socket, Opts, Body). + +request(Socket, Opts, Body) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{active, once}])), + receive + {Protocol, _, {http_request, Method, Path, Version}} when Protocol == http orelse Protocol == ssl -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, httph}])), + headers(Socket, Opts, {Method, Path, Version}, [], Body, 0); + {Protocol, _, {http_error, "\r\n"}} when Protocol == http orelse Protocol == ssl -> + request(Socket, Opts, Body); + {Protocol, _, {http_error, "\n"}} when Protocol == http orelse Protocol == ssl -> + request(Socket, Opts, Body); + {tcp_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {ssl_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal) + after ?REQUEST_RECV_TIMEOUT -> + mochiweb_socket:close(Socket), + exit(normal) + end. + +reentry(Body) -> + fun (Req) -> + ?MODULE:after_response(Body, Req) + end. + +headers(Socket, Opts, Request, Headers, _Body, ?MAX_HEADERS) -> + %% Too many headers sent, bad request. + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, raw}])), + handle_invalid_request(Socket, Opts, Request, Headers); +headers(Socket, Opts, Request, Headers, Body, HeaderCount) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{active, once}])), + receive + {Protocol, _, http_eoh} when Protocol == http orelse Protocol == ssl -> + Req = new_request(Socket, Opts, Request, Headers), + call_body(Body, Req), + ?MODULE:after_response(Body, Req); + {Protocol, _, {http_header, _, Name, _, Value}} when Protocol == http orelse Protocol == ssl -> + headers(Socket, Opts, Request, [{Name, Value} | Headers], Body, + 1 + HeaderCount); + {tcp_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {tcp_error, _, emsgsize} = Other -> + handle_invalid_msg_request(Other, Socket, Opts, Request, Headers) + after ?HEADERS_RECV_TIMEOUT -> + mochiweb_socket:close(Socket), + exit(normal) + end. + +call_body({M, F, A}, Req) -> + erlang:apply(M, F, [Req | A]); +call_body({M, F}, Req) -> + M:F(Req); +call_body(Body, Req) -> + Body(Req). + +-spec handle_invalid_msg_request(term(), term(), term(), term(), term()) -> no_return(). +handle_invalid_msg_request(Msg, Socket, Opts, Request, RevHeaders) -> + case {Msg, r15b_workaround()} of + {{tcp_error,_,emsgsize}, true} -> + %% R15B02 returns this then closes the socket, so close and exit + mochiweb_socket:close(Socket), + exit(normal); + _ -> + handle_invalid_request(Socket, Opts, Request, RevHeaders) + end. + +-spec handle_invalid_request(term(), term(), term(), term()) -> no_return(). +handle_invalid_request(Socket, Opts, Request, RevHeaders) -> + Req = new_request(Socket, Opts, Request, RevHeaders), + Req:respond({400, [], []}), + mochiweb_socket:close(Socket), + exit(normal). + +new_request(Socket, Opts, Request, RevHeaders) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, raw}])), + mochiweb:new_request({Socket, Opts, Request, lists:reverse(RevHeaders)}). + +after_response(Body, Req) -> + Socket = Req:get(socket), + case Req:should_close() of + true -> + mochiweb_socket:close(Socket), + exit(normal); + false -> + Req:cleanup(), + erlang:garbage_collect(), + ?MODULE:loop(Socket, mochiweb_request:get(opts, Req), Body) + end. + +parse_range_request(RawRange) when is_list(RawRange) -> + try + "bytes=" ++ RangeString = RawRange, + RangeTokens = [string:strip(R) || R <- string:tokens(RangeString, ",")], + Ranges = [R || R <- RangeTokens, string:len(R) > 0], + lists:map(fun ("-" ++ V) -> + {none, list_to_integer(V)}; + (R) -> + case string:tokens(R, "-") of + [S1, S2] -> + {list_to_integer(S1), list_to_integer(S2)}; + [S] -> + {list_to_integer(S), none} + end + end, + Ranges) + catch + _:_ -> + fail + end. + +range_skip_length(Spec, Size) -> + case Spec of + {none, R} when R =< Size, R >= 0 -> + {Size - R, R}; + {none, _OutOfRange} -> + {0, Size}; + {R, none} when R >= 0, R < Size -> + {R, Size - R}; + {_OutOfRange, none} -> + invalid_range; + {Start, End} when Start >= 0, Start < Size, Start =< End -> + {Start, erlang:min(End + 1, Size) - Start}; + {_InvalidStart, _InvalidEnd} -> + invalid_range + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +range_test() -> + %% valid, single ranges + ?assertEqual([{20, 30}], parse_range_request("bytes=20-30")), + ?assertEqual([{20, none}], parse_range_request("bytes=20-")), + ?assertEqual([{none, 20}], parse_range_request("bytes=-20")), + + %% trivial single range + ?assertEqual([{0, none}], parse_range_request("bytes=0-")), + + %% invalid, single ranges + ?assertEqual(fail, parse_range_request("")), + ?assertEqual(fail, parse_range_request("garbage")), + ?assertEqual(fail, parse_range_request("bytes=-20-30")), + + %% valid, multiple range + ?assertEqual( + [{20, 30}, {50, 100}, {110, 200}], + parse_range_request("bytes=20-30,50-100,110-200")), + ?assertEqual( + [{20, none}, {50, 100}, {none, 200}], + parse_range_request("bytes=20-,50-100,-200")), + + %% valid, multiple range with whitespace + ?assertEqual( + [{20, 30}, {50, 100}, {110, 200}], + parse_range_request("bytes=20-30, 50-100 , 110-200")), + + %% valid, multiple range with extra commas + ?assertEqual( + [{20, 30}, {50, 100}, {110, 200}], + parse_range_request("bytes=20-30,,50-100,110-200")), + ?assertEqual( + [{20, 30}, {50, 100}, {110, 200}], + parse_range_request("bytes=20-30, ,50-100,,,110-200")), + + %% no ranges + ?assertEqual([], parse_range_request("bytes=")), + ok. + +range_skip_length_test() -> + Body = <<"012345678901234567890123456789012345678901234567890123456789">>, + BodySize = byte_size(Body), %% 60 + BodySize = 60, + + %% these values assume BodySize =:= 60 + ?assertEqual({1,9}, range_skip_length({1,9}, BodySize)), %% 1-9 + ?assertEqual({10,10}, range_skip_length({10,19}, BodySize)), %% 10-19 + ?assertEqual({40, 20}, range_skip_length({none, 20}, BodySize)), %% -20 + ?assertEqual({30, 30}, range_skip_length({30, none}, BodySize)), %% 30- + + %% valid edge cases for range_skip_length + ?assertEqual({BodySize, 0}, range_skip_length({none, 0}, BodySize)), + ?assertEqual({0, BodySize}, range_skip_length({none, BodySize}, BodySize)), + ?assertEqual({0, BodySize}, range_skip_length({0, none}, BodySize)), + ?assertEqual({0, BodySize}, range_skip_length({0, BodySize + 1}, BodySize)), + BodySizeLess1 = BodySize - 1, + ?assertEqual({BodySizeLess1, 1}, + range_skip_length({BodySize - 1, none}, BodySize)), + ?assertEqual({BodySizeLess1, 1}, + range_skip_length({BodySize - 1, BodySize+5}, BodySize)), + ?assertEqual({BodySizeLess1, 1}, + range_skip_length({BodySize - 1, BodySize}, BodySize)), + + %% out of range, return whole thing + ?assertEqual({0, BodySize}, + range_skip_length({none, BodySize + 1}, BodySize)), + ?assertEqual({0, BodySize}, + range_skip_length({none, -1}, BodySize)), + ?assertEqual({0, BodySize}, + range_skip_length({0, BodySize + 1}, BodySize)), + + %% invalid ranges + ?assertEqual(invalid_range, + range_skip_length({-1, 30}, BodySize)), + ?assertEqual(invalid_range, + range_skip_length({-1, BodySize + 1}, BodySize)), + ?assertEqual(invalid_range, + range_skip_length({BodySize, 40}, BodySize)), + ?assertEqual(invalid_range, + range_skip_length({-1, none}, BodySize)), + ?assertEqual(invalid_range, + range_skip_length({BodySize, none}, BodySize)), + ?assertEqual(invalid_range, + range_skip_length({BodySize + 1, BodySize + 5}, BodySize)), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiweb_io.erl b/deps/mochiweb/src/mochiweb_io.erl new file mode 100644 index 0000000..15b6b3a --- /dev/null +++ b/deps/mochiweb/src/mochiweb_io.erl @@ -0,0 +1,61 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Utilities for dealing with IO devices (open files). + +-module(mochiweb_io). +-author('bob@mochimedia.com'). + +-export([iodevice_stream/3, iodevice_stream/2]). +-export([iodevice_foldl/4, iodevice_foldl/3]). +-export([iodevice_size/1]). +-define(READ_SIZE, 8192). + +iodevice_foldl(F, Acc, IoDevice) -> + iodevice_foldl(F, Acc, IoDevice, ?READ_SIZE). + +iodevice_foldl(F, Acc, IoDevice, BufferSize) -> + case file:read(IoDevice, BufferSize) of + eof -> + Acc; + {ok, Data} -> + iodevice_foldl(F, F(Data, Acc), IoDevice, BufferSize) + end. + +iodevice_stream(Callback, IoDevice) -> + iodevice_stream(Callback, IoDevice, ?READ_SIZE). + +iodevice_stream(Callback, IoDevice, BufferSize) -> + F = fun (Data, ok) -> Callback(Data) end, + ok = iodevice_foldl(F, ok, IoDevice, BufferSize). + +iodevice_size(IoDevice) -> + {ok, Size} = file:position(IoDevice, eof), + {ok, 0} = file:position(IoDevice, bof), + Size. + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochiweb_mime.erl b/deps/mochiweb/src/mochiweb_mime.erl new file mode 100644 index 0000000..949d957 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_mime.erl @@ -0,0 +1,433 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Gives a good MIME type guess based on file extension. + +-module(mochiweb_mime). +-author('bob@mochimedia.com'). +-export([from_extension/1]). + +%% @spec from_extension(S::string()) -> string() | undefined +%% @doc Given a filename extension (e.g. ".html") return a guess for the MIME +%% type such as "text/html". Will return the atom undefined if no good +%% guess is available. + +from_extension(".stl") -> + "application/SLA"; +from_extension(".stp") -> + "application/STEP"; +from_extension(".step") -> + "application/STEP"; +from_extension(".dwg") -> + "application/acad"; +from_extension(".ez") -> + "application/andrew-inset"; +from_extension(".ccad") -> + "application/clariscad"; +from_extension(".drw") -> + "application/drafting"; +from_extension(".tsp") -> + "application/dsptype"; +from_extension(".dxf") -> + "application/dxf"; +from_extension(".xls") -> + "application/excel"; +from_extension(".unv") -> + "application/i-deas"; +from_extension(".jar") -> + "application/java-archive"; +from_extension(".hqx") -> + "application/mac-binhex40"; +from_extension(".cpt") -> + "application/mac-compactpro"; +from_extension(".pot") -> + "application/vnd.ms-powerpoint"; +from_extension(".ppt") -> + "application/vnd.ms-powerpoint"; +from_extension(".dms") -> + "application/octet-stream"; +from_extension(".lha") -> + "application/octet-stream"; +from_extension(".lzh") -> + "application/octet-stream"; +from_extension(".oda") -> + "application/oda"; +from_extension(".ogg") -> + "application/ogg"; +from_extension(".ogm") -> + "application/ogg"; +from_extension(".pdf") -> + "application/pdf"; +from_extension(".pgp") -> + "application/pgp"; +from_extension(".ai") -> + "application/postscript"; +from_extension(".eps") -> + "application/postscript"; +from_extension(".ps") -> + "application/postscript"; +from_extension(".prt") -> + "application/pro_eng"; +from_extension(".rtf") -> + "application/rtf"; +from_extension(".smi") -> + "application/smil"; +from_extension(".smil") -> + "application/smil"; +from_extension(".sol") -> + "application/solids"; +from_extension(".vda") -> + "application/vda"; +from_extension(".xlm") -> + "application/vnd.ms-excel"; +from_extension(".cod") -> + "application/vnd.rim.cod"; +from_extension(".pgn") -> + "application/x-chess-pgn"; +from_extension(".cpio") -> + "application/x-cpio"; +from_extension(".csh") -> + "application/x-csh"; +from_extension(".deb") -> + "application/x-debian-package"; +from_extension(".dcr") -> + "application/x-director"; +from_extension(".dir") -> + "application/x-director"; +from_extension(".dxr") -> + "application/x-director"; +from_extension(".gz") -> + "application/x-gzip"; +from_extension(".hdf") -> + "application/x-hdf"; +from_extension(".ipx") -> + "application/x-ipix"; +from_extension(".ips") -> + "application/x-ipscript"; +from_extension(".js") -> + "application/x-javascript"; +from_extension(".skd") -> + "application/x-koan"; +from_extension(".skm") -> + "application/x-koan"; +from_extension(".skp") -> + "application/x-koan"; +from_extension(".skt") -> + "application/x-koan"; +from_extension(".latex") -> + "application/x-latex"; +from_extension(".lsp") -> + "application/x-lisp"; +from_extension(".scm") -> + "application/x-lotusscreencam"; +from_extension(".mif") -> + "application/x-mif"; +from_extension(".com") -> + "application/x-msdos-program"; +from_extension(".exe") -> + "application/octet-stream"; +from_extension(".cdf") -> + "application/x-netcdf"; +from_extension(".nc") -> + "application/x-netcdf"; +from_extension(".pl") -> + "application/x-perl"; +from_extension(".pm") -> + "application/x-perl"; +from_extension(".rar") -> + "application/x-rar-compressed"; +from_extension(".sh") -> + "application/x-sh"; +from_extension(".shar") -> + "application/x-shar"; +from_extension(".swf") -> + "application/x-shockwave-flash"; +from_extension(".sit") -> + "application/x-stuffit"; +from_extension(".sv4cpio") -> + "application/x-sv4cpio"; +from_extension(".sv4crc") -> + "application/x-sv4crc"; +from_extension(".tar.gz") -> + "application/x-tar-gz"; +from_extension(".tgz") -> + "application/x-tar-gz"; +from_extension(".tar") -> + "application/x-tar"; +from_extension(".tcl") -> + "application/x-tcl"; +from_extension(".texi") -> + "application/x-texinfo"; +from_extension(".texinfo") -> + "application/x-texinfo"; +from_extension(".man") -> + "application/x-troff-man"; +from_extension(".me") -> + "application/x-troff-me"; +from_extension(".ms") -> + "application/x-troff-ms"; +from_extension(".roff") -> + "application/x-troff"; +from_extension(".t") -> + "application/x-troff"; +from_extension(".tr") -> + "application/x-troff"; +from_extension(".ustar") -> + "application/x-ustar"; +from_extension(".src") -> + "application/x-wais-source"; +from_extension(".zip") -> + "application/zip"; +from_extension(".tsi") -> + "audio/TSP-audio"; +from_extension(".au") -> + "audio/basic"; +from_extension(".snd") -> + "audio/basic"; +from_extension(".kar") -> + "audio/midi"; +from_extension(".mid") -> + "audio/midi"; +from_extension(".midi") -> + "audio/midi"; +from_extension(".mp2") -> + "audio/mpeg"; +from_extension(".mp3") -> + "audio/mpeg"; +from_extension(".mpga") -> + "audio/mpeg"; +from_extension(".aif") -> + "audio/x-aiff"; +from_extension(".aifc") -> + "audio/x-aiff"; +from_extension(".aiff") -> + "audio/x-aiff"; +from_extension(".m3u") -> + "audio/x-mpegurl"; +from_extension(".wax") -> + "audio/x-ms-wax"; +from_extension(".wma") -> + "audio/x-ms-wma"; +from_extension(".rpm") -> + "audio/x-pn-realaudio-plugin"; +from_extension(".ram") -> + "audio/x-pn-realaudio"; +from_extension(".rm") -> + "audio/x-pn-realaudio"; +from_extension(".ra") -> + "audio/x-realaudio"; +from_extension(".wav") -> + "audio/x-wav"; +from_extension(".pdb") -> + "chemical/x-pdb"; +from_extension(".ras") -> + "image/cmu-raster"; +from_extension(".gif") -> + "image/gif"; +from_extension(".ief") -> + "image/ief"; +from_extension(".jpe") -> + "image/jpeg"; +from_extension(".jpeg") -> + "image/jpeg"; +from_extension(".jpg") -> + "image/jpeg"; +from_extension(".jp2") -> + "image/jp2"; +from_extension(".png") -> + "image/png"; +from_extension(".tif") -> + "image/tiff"; +from_extension(".tiff") -> + "image/tiff"; +from_extension(".pnm") -> + "image/x-portable-anymap"; +from_extension(".pbm") -> + "image/x-portable-bitmap"; +from_extension(".pgm") -> + "image/x-portable-graymap"; +from_extension(".ppm") -> + "image/x-portable-pixmap"; +from_extension(".rgb") -> + "image/x-rgb"; +from_extension(".xbm") -> + "image/x-xbitmap"; +from_extension(".xwd") -> + "image/x-xwindowdump"; +from_extension(".iges") -> + "model/iges"; +from_extension(".igs") -> + "model/iges"; +from_extension(".mesh") -> + "model/mesh"; +from_extension(".") -> + ""; +from_extension(".msh") -> + "model/mesh"; +from_extension(".silo") -> + "model/mesh"; +from_extension(".vrml") -> + "model/vrml"; +from_extension(".wrl") -> + "model/vrml"; +from_extension(".css") -> + "text/css"; +from_extension(".htm") -> + "text/html"; +from_extension(".html") -> + "text/html"; +from_extension(".asc") -> + "text/plain"; +from_extension(".c") -> + "text/plain"; +from_extension(".cc") -> + "text/plain"; +from_extension(".f90") -> + "text/plain"; +from_extension(".f") -> + "text/plain"; +from_extension(".hh") -> + "text/plain"; +from_extension(".m") -> + "text/plain"; +from_extension(".txt") -> + "text/plain"; +from_extension(".rtx") -> + "text/richtext"; +from_extension(".sgm") -> + "text/sgml"; +from_extension(".sgml") -> + "text/sgml"; +from_extension(".tsv") -> + "text/tab-separated-values"; +from_extension(".jad") -> + "text/vnd.sun.j2me.app-descriptor"; +from_extension(".etx") -> + "text/x-setext"; +from_extension(".xml") -> + "application/xml"; +from_extension(".dl") -> + "video/dl"; +from_extension(".fli") -> + "video/fli"; +from_extension(".flv") -> + "video/x-flv"; +from_extension(".gl") -> + "video/gl"; +from_extension(".mp4") -> + "video/mp4"; +from_extension(".mpe") -> + "video/mpeg"; +from_extension(".mpeg") -> + "video/mpeg"; +from_extension(".mpg") -> + "video/mpeg"; +from_extension(".mov") -> + "video/quicktime"; +from_extension(".qt") -> + "video/quicktime"; +from_extension(".viv") -> + "video/vnd.vivo"; +from_extension(".vivo") -> + "video/vnd.vivo"; +from_extension(".asf") -> + "video/x-ms-asf"; +from_extension(".asx") -> + "video/x-ms-asx"; +from_extension(".wmv") -> + "video/x-ms-wmv"; +from_extension(".wmx") -> + "video/x-ms-wmx"; +from_extension(".wvx") -> + "video/x-ms-wvx"; +from_extension(".avi") -> + "video/x-msvideo"; +from_extension(".movie") -> + "video/x-sgi-movie"; +from_extension(".mime") -> + "www/mime"; +from_extension(".ice") -> + "x-conference/x-cooltalk"; +from_extension(".vrm") -> + "x-world/x-vrml"; +from_extension(".spx") -> + "audio/ogg"; +from_extension(".xhtml") -> + "application/xhtml+xml"; +from_extension(".bz2") -> + "application/x-bzip2"; +from_extension(".doc") -> + "application/msword"; +from_extension(".z") -> + "application/x-compress"; +from_extension(".ico") -> + "image/x-icon"; +from_extension(".bmp") -> + "image/bmp"; +from_extension(".m4a") -> + "audio/mpeg"; +from_extension(".csv") -> + "text/csv"; +from_extension(".eot") -> + "application/vnd.ms-fontobject"; +from_extension(".m4v") -> + "video/mp4"; +from_extension(".svg") -> + "image/svg+xml"; +from_extension(".svgz") -> + "image/svg+xml"; +from_extension(".ttc") -> + "application/x-font-ttf"; +from_extension(".ttf") -> + "application/x-font-ttf"; +from_extension(".vcf") -> + "text/x-vcard"; +from_extension(".webm") -> + "video/web"; +from_extension(".webp") -> + "image/web"; +from_extension(".woff") -> + "application/x-font-woff"; +from_extension(".otf") -> + "font/opentype"; +from_extension(_) -> + undefined. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +exhaustive_from_extension_test() -> + T = mochiweb_cover:clause_lookup_table(?MODULE, from_extension), + [?assertEqual(V, from_extension(K)) || {K, V} <- T]. + +from_extension_test() -> + ?assertEqual("text/html", + from_extension(".html")), + ?assertEqual(undefined, + from_extension("")), + ?assertEqual(undefined, + from_extension(".wtf")), + ok. + +-endif. diff --git a/deps/mochiweb/src/mochiweb_multipart.erl b/deps/mochiweb/src/mochiweb_multipart.erl new file mode 100644 index 0000000..1d18ae2 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_multipart.erl @@ -0,0 +1,890 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Utilities for parsing multipart/form-data. + +-module(mochiweb_multipart). +-author('bob@mochimedia.com'). + +-export([parse_form/1, parse_form/2]). +-export([parse_multipart_request/2]). +-export([parts_to_body/3, parts_to_multipart_body/4]). +-export([default_file_handler/2]). + +-define(CHUNKSIZE, 4096). + +-record(mp, {state, boundary, length, buffer, callback, req}). + +%% TODO: DOCUMENT THIS MODULE. +%% @type key() = atom() | string() | binary(). +%% @type value() = atom() | iolist() | integer(). +%% @type header() = {key(), value()}. +%% @type bodypart() = {Start::integer(), End::integer(), Body::iolist()}. +%% @type formfile() = {Name::string(), ContentType::string(), Content::binary()}. +%% @type request(). +%% @type file_handler() = (Filename::string(), ContentType::string()) -> file_handler_callback(). +%% @type file_handler_callback() = (binary() | eof) -> file_handler_callback() | term(). + +%% @spec parts_to_body([bodypart()], ContentType::string(), +%% Size::integer()) -> {[header()], iolist()} +%% @doc Return {[header()], iolist()} representing the body for the given +%% parts, may be a single part or multipart. +parts_to_body([{Start, End, Body}], ContentType, Size) -> + HeaderList = [{"Content-Type", ContentType}, + {"Content-Range", + ["bytes ", + mochiweb_util:make_io(Start), "-", mochiweb_util:make_io(End), + "/", mochiweb_util:make_io(Size)]}], + {HeaderList, Body}; +parts_to_body(BodyList, ContentType, Size) when is_list(BodyList) -> + parts_to_multipart_body(BodyList, ContentType, Size, + mochihex:to_hex(crypto:rand_bytes(8))). + +%% @spec parts_to_multipart_body([bodypart()], ContentType::string(), +%% Size::integer(), Boundary::string()) -> +%% {[header()], iolist()} +%% @doc Return {[header()], iolist()} representing the body for the given +%% parts, always a multipart response. +parts_to_multipart_body(BodyList, ContentType, Size, Boundary) -> + HeaderList = [{"Content-Type", + ["multipart/byteranges; ", + "boundary=", Boundary]}], + MultiPartBody = multipart_body(BodyList, ContentType, Boundary, Size), + + {HeaderList, MultiPartBody}. + +%% @spec multipart_body([bodypart()], ContentType::string(), +%% Boundary::string(), Size::integer()) -> iolist() +%% @doc Return the representation of a multipart body for the given [bodypart()]. +multipart_body([], _ContentType, Boundary, _Size) -> + ["--", Boundary, "--\r\n"]; +multipart_body([{Start, End, Body} | BodyList], ContentType, Boundary, Size) -> + ["--", Boundary, "\r\n", + "Content-Type: ", ContentType, "\r\n", + "Content-Range: ", + "bytes ", mochiweb_util:make_io(Start), "-", mochiweb_util:make_io(End), + "/", mochiweb_util:make_io(Size), "\r\n\r\n", + Body, "\r\n" + | multipart_body(BodyList, ContentType, Boundary, Size)]. + +%% @spec parse_form(request()) -> [{string(), string() | formfile()}] +%% @doc Parse a multipart form from the given request using the in-memory +%% default_file_handler/2. +parse_form(Req) -> + parse_form(Req, fun default_file_handler/2). + +%% @spec parse_form(request(), F::file_handler()) -> [{string(), string() | term()}] +%% @doc Parse a multipart form from the given request using the given file_handler(). +parse_form(Req, FileHandler) -> + Callback = fun (Next) -> parse_form_outer(Next, FileHandler, []) end, + {_, _, Res} = parse_multipart_request(Req, Callback), + Res. + +parse_form_outer(eof, _, Acc) -> + lists:reverse(Acc); +parse_form_outer({headers, H}, FileHandler, State) -> + {"form-data", H1} = proplists:get_value("content-disposition", H), + Name = proplists:get_value("name", H1), + Filename = proplists:get_value("filename", H1), + case Filename of + undefined -> + fun (Next) -> + parse_form_value(Next, {Name, []}, FileHandler, State) + end; + _ -> + ContentType = proplists:get_value("content-type", H), + Handler = FileHandler(Filename, ContentType), + fun (Next) -> + parse_form_file(Next, {Name, Handler}, FileHandler, State) + end + end. + +parse_form_value(body_end, {Name, Acc}, FileHandler, State) -> + Value = binary_to_list(iolist_to_binary(lists:reverse(Acc))), + State1 = [{Name, Value} | State], + fun (Next) -> parse_form_outer(Next, FileHandler, State1) end; +parse_form_value({body, Data}, {Name, Acc}, FileHandler, State) -> + Acc1 = [Data | Acc], + fun (Next) -> parse_form_value(Next, {Name, Acc1}, FileHandler, State) end. + +parse_form_file(body_end, {Name, Handler}, FileHandler, State) -> + Value = Handler(eof), + State1 = [{Name, Value} | State], + fun (Next) -> parse_form_outer(Next, FileHandler, State1) end; +parse_form_file({body, Data}, {Name, Handler}, FileHandler, State) -> + H1 = Handler(Data), + fun (Next) -> parse_form_file(Next, {Name, H1}, FileHandler, State) end. + +default_file_handler(Filename, ContentType) -> + default_file_handler_1(Filename, ContentType, []). + +default_file_handler_1(Filename, ContentType, Acc) -> + fun(eof) -> + Value = iolist_to_binary(lists:reverse(Acc)), + {Filename, ContentType, Value}; + (Next) -> + default_file_handler_1(Filename, ContentType, [Next | Acc]) + end. + +parse_multipart_request(Req, Callback) -> + %% TODO: Support chunked? + Length = list_to_integer(Req:get_combined_header_value("content-length")), + Boundary = iolist_to_binary( + get_boundary(Req:get_header_value("content-type"))), + Prefix = <<"\r\n--", Boundary/binary>>, + BS = byte_size(Boundary), + Chunk = read_chunk(Req, Length), + Length1 = Length - byte_size(Chunk), + <<"--", Boundary:BS/binary, "\r\n", Rest/binary>> = Chunk, + feed_mp(headers, flash_multipart_hack(#mp{boundary=Prefix, + length=Length1, + buffer=Rest, + callback=Callback, + req=Req})). + +parse_headers(<<>>) -> + []; +parse_headers(Binary) -> + parse_headers(Binary, []). + +parse_headers(Binary, Acc) -> + case find_in_binary(<<"\r\n">>, Binary) of + {exact, N} -> + <> = Binary, + parse_headers(Rest, [split_header(Line) | Acc]); + not_found -> + lists:reverse([split_header(Binary) | Acc]) + end. + +split_header(Line) -> + {Name, [$: | Value]} = lists:splitwith(fun (C) -> C =/= $: end, + binary_to_list(Line)), + {string:to_lower(string:strip(Name)), + mochiweb_util:parse_header(Value)}. + +read_chunk(Req, Length) when Length > 0 -> + case Length of + Length when Length < ?CHUNKSIZE -> + Req:recv(Length); + _ -> + Req:recv(?CHUNKSIZE) + end. + +read_more(State=#mp{length=Length, buffer=Buffer, req=Req}) -> + Data = read_chunk(Req, Length), + Buffer1 = <>, + flash_multipart_hack(State#mp{length=Length - byte_size(Data), + buffer=Buffer1}). + +flash_multipart_hack(State=#mp{length=0, buffer=Buffer, boundary=Prefix}) -> + %% http://code.google.com/p/mochiweb/issues/detail?id=22 + %% Flash doesn't terminate multipart with \r\n properly so we fix it up here + PrefixSize = size(Prefix), + case size(Buffer) - (2 + PrefixSize) of + Seek when Seek >= 0 -> + case Buffer of + <<_:Seek/binary, Prefix:PrefixSize/binary, "--">> -> + Buffer1 = <>, + State#mp{buffer=Buffer1}; + _ -> + State + end; + _ -> + State + end; +flash_multipart_hack(State) -> + State. + +feed_mp(headers, State=#mp{buffer=Buffer, callback=Callback}) -> + {State1, P} = case find_in_binary(<<"\r\n\r\n">>, Buffer) of + {exact, N} -> + {State, N}; + _ -> + S1 = read_more(State), + %% Assume headers must be less than ?CHUNKSIZE + {exact, N} = find_in_binary(<<"\r\n\r\n">>, + S1#mp.buffer), + {S1, N} + end, + <> = State1#mp.buffer, + NextCallback = Callback({headers, parse_headers(Headers)}), + feed_mp(body, State1#mp{buffer=Rest, + callback=NextCallback}); +feed_mp(body, State=#mp{boundary=Prefix, buffer=Buffer, callback=Callback}) -> + Boundary = find_boundary(Prefix, Buffer), + case Boundary of + {end_boundary, Start, Skip} -> + <> = Buffer, + C1 = Callback({body, Data}), + C2 = C1(body_end), + {State#mp.length, Rest, C2(eof)}; + {next_boundary, Start, Skip} -> + <> = Buffer, + C1 = Callback({body, Data}), + feed_mp(headers, State#mp{callback=C1(body_end), + buffer=Rest}); + {maybe, Start} -> + <> = Buffer, + feed_mp(body, read_more(State#mp{callback=Callback({body, Data}), + buffer=Rest})); + not_found -> + {Data, Rest} = {Buffer, <<>>}, + feed_mp(body, read_more(State#mp{callback=Callback({body, Data}), + buffer=Rest})) + end. + +get_boundary(ContentType) -> + {"multipart/form-data", Opts} = mochiweb_util:parse_header(ContentType), + case proplists:get_value("boundary", Opts) of + S when is_list(S) -> + S + end. + +%% @spec find_in_binary(Pattern::binary(), Data::binary()) -> +%% {exact, N} | {partial, N, K} | not_found +%% @doc Searches for the given pattern in the given binary. +find_in_binary(P, Data) when size(P) > 0 -> + PS = size(P), + DS = size(Data), + case DS - PS of + Last when Last < 0 -> + partial_find(P, Data, 0, DS); + Last -> + case binary:match(Data, P) of + {Pos, _} -> {exact, Pos}; + nomatch -> partial_find(P, Data, Last+1, PS-1) + end + end. + +partial_find(_B, _D, _N, 0) -> + not_found; +partial_find(B, D, N, K) -> + <> = B, + case D of + <<_Skip:N/binary, B1:K/binary>> -> + {partial, N, K}; + _ -> + partial_find(B, D, 1 + N, K - 1) + end. + +find_boundary(Prefix, Data) -> + case find_in_binary(Prefix, Data) of + {exact, Skip} -> + PrefixSkip = Skip + size(Prefix), + case Data of + <<_:PrefixSkip/binary, "\r\n", _/binary>> -> + {next_boundary, Skip, size(Prefix) + 2}; + <<_:PrefixSkip/binary, "--\r\n", _/binary>> -> + {end_boundary, Skip, size(Prefix) + 4}; + _ when size(Data) < PrefixSkip + 4 -> + %% Underflow + {maybe, Skip}; + _ -> + %% False positive + not_found + end; + {partial, Skip, Length} when (Skip + Length) =:= size(Data) -> + %% Underflow + {maybe, Skip}; + _ -> + not_found + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +ssl_cert_opts() -> + EbinDir = filename:dirname(code:which(?MODULE)), + CertDir = filename:join([EbinDir, "..", "support", "test-materials"]), + CertFile = filename:join(CertDir, "test_ssl_cert.pem"), + KeyFile = filename:join(CertDir, "test_ssl_key.pem"), + [{certfile, CertFile}, {keyfile, KeyFile}]. + +with_socket_server(Transport, ServerFun, ClientFun) -> + ServerOpts0 = [{ip, "127.0.0.1"}, {port, 0}, {loop, ServerFun}], + ServerOpts = case Transport of + plain -> + ServerOpts0; + ssl -> + ServerOpts0 ++ [{ssl, true}, {ssl_opts, ssl_cert_opts()}] + end, + {ok, Server} = mochiweb_socket_server:start_link(ServerOpts), + Port = mochiweb_socket_server:get(Server, port), + ClientOpts = [binary, {active, false}], + {ok, Client} = case Transport of + plain -> + gen_tcp:connect("127.0.0.1", Port, ClientOpts); + ssl -> + ClientOpts1 = [{ssl_imp, new} | ClientOpts], + {ok, SslSocket} = ssl:connect("127.0.0.1", Port, ClientOpts1), + {ok, {ssl, SslSocket}} + end, + Res = (catch ClientFun(Client)), + mochiweb_socket_server:stop(Server), + Res. + +fake_request(Socket, ContentType, Length) -> + mochiweb_request:new(Socket, + 'POST', + "/multipart", + {1,1}, + mochiweb_headers:make( + [{"content-type", ContentType}, + {"content-length", Length}])). + +test_callback({body, <<>>}, Rest=[body_end | _]) -> + %% When expecting the body_end we might get an empty binary + fun (Next) -> test_callback(Next, Rest) end; +test_callback({body, Got}, [{body, Expect} | Rest]) when Got =/= Expect -> + %% Partial response + GotSize = size(Got), + <> = Expect, + fun (Next) -> test_callback(Next, [{body, Expect1} | Rest]) end; +test_callback(Got, [Expect | Rest]) -> + ?assertEqual(Got, Expect), + case Rest of + [] -> + ok; + _ -> + fun (Next) -> test_callback(Next, Rest) end + end. + +parse3_http_test() -> + parse3(plain). + +parse3_https_test() -> + parse3(ssl). + +parse3(Transport) -> + ContentType = "multipart/form-data; boundary=---------------------------7386909285754635891697677882", + BinContent = <<"-----------------------------7386909285754635891697677882\r\nContent-Disposition: form-data; name=\"hidden\"\r\n\r\nmultipart message\r\n-----------------------------7386909285754635891697677882\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test_file.txt\"\r\nContent-Type: text/plain\r\n\r\nWoo multiline text file\n\nLa la la\r\n-----------------------------7386909285754635891697677882--\r\n">>, + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "hidden"}]}}]}, + {body, <<"multipart message">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "file"}, {"filename", "test_file.txt"}]}}, + {"content-type", {"text/plain", []}}]}, + {body, <<"Woo multiline text file\n\nLa la la">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse2_http_test() -> + parse2(plain). + +parse2_https_test() -> + parse2(ssl). + +parse2(Transport) -> + ContentType = "multipart/form-data; boundary=---------------------------6072231407570234361599764024", + BinContent = <<"-----------------------------6072231407570234361599764024\r\nContent-Disposition: form-data; name=\"hidden\"\r\n\r\nmultipart message\r\n-----------------------------6072231407570234361599764024\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----------------------------6072231407570234361599764024--\r\n">>, + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "hidden"}]}}]}, + {body, <<"multipart message">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "file"}, {"filename", ""}]}}, + {"content-type", {"application/octet-stream", []}}]}, + {body, <<>>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse_form_http_test() -> + do_parse_form(plain). + +parse_form_https_test() -> + do_parse_form(ssl). + +do_parse_form(Transport) -> + ContentType = "multipart/form-data; boundary=AaB03x", + "AaB03x" = get_boundary(ContentType), + Content = mochiweb_util:join( + ["--AaB03x", + "Content-Disposition: form-data; name=\"submit-name\"", + "", + "Larry", + "--AaB03x", + "Content-Disposition: form-data; name=\"files\";" + ++ "filename=\"file1.txt\"", + "Content-Type: text/plain", + "", + "... contents of file1.txt ...", + "--AaB03x--", + ""], "\r\n"), + BinContent = iolist_to_binary(Content), + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_form(Req), + [{"submit-name", "Larry"}, + {"files", {"file1.txt", {"text/plain",[]}, + <<"... contents of file1.txt ...">>} + }] = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse_http_test() -> + do_parse(plain). + +parse_https_test() -> + do_parse(ssl). + +do_parse(Transport) -> + ContentType = "multipart/form-data; boundary=AaB03x", + "AaB03x" = get_boundary(ContentType), + Content = mochiweb_util:join( + ["--AaB03x", + "Content-Disposition: form-data; name=\"submit-name\"", + "", + "Larry", + "--AaB03x", + "Content-Disposition: form-data; name=\"files\";" + ++ "filename=\"file1.txt\"", + "Content-Type: text/plain", + "", + "... contents of file1.txt ...", + "--AaB03x--", + ""], "\r\n"), + BinContent = iolist_to_binary(Content), + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "submit-name"}]}}]}, + {body, <<"Larry">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "files"}, {"filename", "file1.txt"}]}}, + {"content-type", {"text/plain", []}}]}, + {body, <<"... contents of file1.txt ...">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse_partial_body_boundary_http_test() -> + parse_partial_body_boundary(plain). + +parse_partial_body_boundary_https_test() -> + parse_partial_body_boundary(ssl). + +parse_partial_body_boundary(Transport) -> + Boundary = string:copies("$", 2048), + ContentType = "multipart/form-data; boundary=" ++ Boundary, + ?assertEqual(Boundary, get_boundary(ContentType)), + Content = mochiweb_util:join( + ["--" ++ Boundary, + "Content-Disposition: form-data; name=\"submit-name\"", + "", + "Larry", + "--" ++ Boundary, + "Content-Disposition: form-data; name=\"files\";" + ++ "filename=\"file1.txt\"", + "Content-Type: text/plain", + "", + "... contents of file1.txt ...", + "--" ++ Boundary ++ "--", + ""], "\r\n"), + BinContent = iolist_to_binary(Content), + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "submit-name"}]}}]}, + {body, <<"Larry">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "files"}, {"filename", "file1.txt"}]}}, + {"content-type", {"text/plain", []}} + ]}, + {body, <<"... contents of file1.txt ...">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse_large_header_http_test() -> + parse_large_header(plain). + +parse_large_header_https_test() -> + parse_large_header(ssl). + +parse_large_header(Transport) -> + ContentType = "multipart/form-data; boundary=AaB03x", + "AaB03x" = get_boundary(ContentType), + Content = mochiweb_util:join( + ["--AaB03x", + "Content-Disposition: form-data; name=\"submit-name\"", + "", + "Larry", + "--AaB03x", + "Content-Disposition: form-data; name=\"files\";" + ++ "filename=\"file1.txt\"", + "Content-Type: text/plain", + "x-large-header: " ++ string:copies("%", 4096), + "", + "... contents of file1.txt ...", + "--AaB03x--", + ""], "\r\n"), + BinContent = iolist_to_binary(Content), + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "submit-name"}]}}]}, + {body, <<"Larry">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "files"}, {"filename", "file1.txt"}]}}, + {"content-type", {"text/plain", []}}, + {"x-large-header", {string:copies("%", 4096), []}} + ]}, + {body, <<"... contents of file1.txt ...">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +find_boundary_test() -> + B = <<"\r\n--X">>, + {next_boundary, 0, 7} = find_boundary(B, <<"\r\n--X\r\nRest">>), + {next_boundary, 1, 7} = find_boundary(B, <<"!\r\n--X\r\nRest">>), + {end_boundary, 0, 9} = find_boundary(B, <<"\r\n--X--\r\nRest">>), + {end_boundary, 1, 9} = find_boundary(B, <<"!\r\n--X--\r\nRest">>), + not_found = find_boundary(B, <<"--X\r\nRest">>), + {maybe, 0} = find_boundary(B, <<"\r\n--X\r">>), + {maybe, 1} = find_boundary(B, <<"!\r\n--X\r">>), + P = <<"\r\n-----------------------------16037454351082272548568224146">>, + B0 = <<55,212,131,77,206,23,216,198,35,87,252,118,252,8,25,211,132,229, + 182,42,29,188,62,175,247,243,4,4,0,59, 13,10,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45, + 49,54,48,51,55,52,53,52,51,53,49>>, + {maybe, 30} = find_boundary(P, B0), + not_found = find_boundary(B, <<"\r\n--XJOPKE">>), + ok. + +find_in_binary_test() -> + {exact, 0} = find_in_binary(<<"foo">>, <<"foobarbaz">>), + {exact, 1} = find_in_binary(<<"oo">>, <<"foobarbaz">>), + {exact, 8} = find_in_binary(<<"z">>, <<"foobarbaz">>), + not_found = find_in_binary(<<"q">>, <<"foobarbaz">>), + {partial, 7, 2} = find_in_binary(<<"azul">>, <<"foobarbaz">>), + {exact, 0} = find_in_binary(<<"foobarbaz">>, <<"foobarbaz">>), + {partial, 0, 3} = find_in_binary(<<"foobar">>, <<"foo">>), + {partial, 1, 3} = find_in_binary(<<"foobar">>, <<"afoo">>), + ok. + +flash_parse_http_test() -> + flash_parse(plain). + +flash_parse_https_test() -> + flash_parse(ssl). + +flash_parse(Transport) -> + ContentType = "multipart/form-data; boundary=----------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5", + "----------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5" = get_boundary(ContentType), + BinContent = <<"------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Filename\"\r\n\r\nhello.txt\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"file\"; filename=\"hello.txt\"\r\nContent-Type: application/octet-stream\r\n\r\nhello\n\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Upload\"\r\n\r\nSubmit Query\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5--">>, + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "Filename"}]}}]}, + {body, <<"hello.txt">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "success_action_status"}]}}]}, + {body, <<"201">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "file"}, {"filename", "hello.txt"}]}}, + {"content-type", {"application/octet-stream", []}}]}, + {body, <<"hello\n">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "Upload"}]}}]}, + {body, <<"Submit Query">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +flash_parse2_http_test() -> + flash_parse2(plain). + +flash_parse2_https_test() -> + flash_parse2(ssl). + +flash_parse2(Transport) -> + ContentType = "multipart/form-data; boundary=----------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5", + "----------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5" = get_boundary(ContentType), + Chunk = iolist_to_binary(string:copies("%", 4096)), + BinContent = <<"------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Filename\"\r\n\r\nhello.txt\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"file\"; filename=\"hello.txt\"\r\nContent-Type: application/octet-stream\r\n\r\n", Chunk/binary, "\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Upload\"\r\n\r\nSubmit Query\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5--">>, + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "Filename"}]}}]}, + {body, <<"hello.txt">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "success_action_status"}]}}]}, + {body, <<"201">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "file"}, {"filename", "hello.txt"}]}}, + {"content-type", {"application/octet-stream", []}}]}, + {body, Chunk}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "Upload"}]}}]}, + {body, <<"Submit Query">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(Transport, ServerFun, ClientFun), + ok. + +parse_headers_test() -> + ?assertEqual([], parse_headers(<<>>)). + +flash_multipart_hack_test() -> + Buffer = <<"prefix-">>, + Prefix = <<"prefix">>, + State = #mp{length=0, buffer=Buffer, boundary=Prefix}, + ?assertEqual(State, + flash_multipart_hack(State)). + +parts_to_body_single_test() -> + {HL, B} = parts_to_body([{0, 5, <<"01234">>}], + "text/plain", + 10), + [{"Content-Range", Range}, + {"Content-Type", Type}] = lists:sort(HL), + ?assertEqual( + <<"bytes 0-5/10">>, + iolist_to_binary(Range)), + ?assertEqual( + <<"text/plain">>, + iolist_to_binary(Type)), + ?assertEqual( + <<"01234">>, + iolist_to_binary(B)), + ok. + +parts_to_body_multi_test() -> + {[{"Content-Type", Type}], + _B} = parts_to_body([{0, 5, <<"01234">>}, {5, 10, <<"56789">>}], + "text/plain", + 10), + ?assertMatch( + <<"multipart/byteranges; boundary=", _/binary>>, + iolist_to_binary(Type)), + ok. + +parts_to_multipart_body_test() -> + {[{"Content-Type", V}], B} = parts_to_multipart_body( + [{0, 5, <<"01234">>}, {5, 10, <<"56789">>}], + "text/plain", + 10, + "BOUNDARY"), + MB = multipart_body( + [{0, 5, <<"01234">>}, {5, 10, <<"56789">>}], + "text/plain", + "BOUNDARY", + 10), + ?assertEqual( + <<"multipart/byteranges; boundary=BOUNDARY">>, + iolist_to_binary(V)), + ?assertEqual( + iolist_to_binary(MB), + iolist_to_binary(B)), + ok. + +multipart_body_test() -> + ?assertEqual( + <<"--BOUNDARY--\r\n">>, + iolist_to_binary(multipart_body([], "text/plain", "BOUNDARY", 0))), + ?assertEqual( + <<"--BOUNDARY\r\n" + "Content-Type: text/plain\r\n" + "Content-Range: bytes 0-5/10\r\n\r\n" + "01234\r\n" + "--BOUNDARY\r\n" + "Content-Type: text/plain\r\n" + "Content-Range: bytes 5-10/10\r\n\r\n" + "56789\r\n" + "--BOUNDARY--\r\n">>, + iolist_to_binary(multipart_body([{0, 5, <<"01234">>}, {5, 10, <<"56789">>}], + "text/plain", + "BOUNDARY", + 10))), + ok. + +%% @todo Move somewhere more appropriate than in the test suite + +multipart_parsing_benchmark_test() -> + run_multipart_parsing_benchmark(1). + +run_multipart_parsing_benchmark(0) -> ok; +run_multipart_parsing_benchmark(N) -> + multipart_parsing_benchmark(), + run_multipart_parsing_benchmark(N-1). + +multipart_parsing_benchmark() -> + ContentType = "multipart/form-data; boundary=----------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5", + Chunk = binary:copy(<<"This Is_%Some=Quite0Long4String2Used9For7BenchmarKing.5">>, 102400), + BinContent = <<"------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Filename\"\r\n\r\nhello.txt\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"success_action_status\"\r\n\r\n201\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"file\"; filename=\"hello.txt\"\r\nContent-Type: application/octet-stream\r\n\r\n", Chunk/binary, "\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5\r\nContent-Disposition: form-data; name=\"Upload\"\r\n\r\nSubmit Query\r\n------------ei4GI3GI3Ij5Ef1ae0KM7Ij5ei4Ij5--">>, + Expect = [{headers, + [{"content-disposition", + {"form-data", [{"name", "Filename"}]}}]}, + {body, <<"hello.txt">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "success_action_status"}]}}]}, + {body, <<"201">>}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "file"}, {"filename", "hello.txt"}]}}, + {"content-type", {"application/octet-stream", []}}]}, + {body, Chunk}, + body_end, + {headers, + [{"content-disposition", + {"form-data", [{"name", "Upload"}]}}]}, + {body, <<"Submit Query">>}, + body_end, + eof], + TestCallback = fun (Next) -> test_callback(Next, Expect) end, + ServerFun = fun (Socket, _Opts) -> + ok = mochiweb_socket:send(Socket, BinContent), + exit(normal) + end, + ClientFun = fun (Socket) -> + Req = fake_request(Socket, ContentType, + byte_size(BinContent)), + Res = parse_multipart_request(Req, TestCallback), + {0, <<>>, ok} = Res, + ok + end, + ok = with_socket_server(plain, ServerFun, ClientFun), + ok. +-endif. diff --git a/deps/mochiweb/src/mochiweb_request.erl b/deps/mochiweb/src/mochiweb_request.erl new file mode 100644 index 0000000..39890ce --- /dev/null +++ b/deps/mochiweb/src/mochiweb_request.erl @@ -0,0 +1,904 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc MochiWeb HTTP Request abstraction. + +-module(mochiweb_request). +-author('bob@mochimedia.com'). + +-include_lib("kernel/include/file.hrl"). +-include("internal.hrl"). + +-define(QUIP, "Any of you quaids got a smint?"). + +-export([new/5, new/6]). +-export([get_header_value/2, get_primary_header_value/2, get_combined_header_value/2, get/2, dump/1]). +-export([send/2, recv/2, recv/3, recv_body/1, recv_body/2, stream_body/4, stream_body/5]). +-export([start_response/2, start_response_length/2, start_raw_response/2]). +-export([respond/2, ok/2]). +-export([not_found/1, not_found/2]). +-export([parse_post/1, parse_qs/1]). +-export([should_close/1, cleanup/1]). +-export([parse_cookie/1, get_cookie_value/2]). +-export([serve_file/3, serve_file/4]). +-export([accepted_encodings/2]). +-export([accepts_content_type/2, accepted_content_types/2]). + +-define(SAVE_QS, mochiweb_request_qs). +-define(SAVE_PATH, mochiweb_request_path). +-define(SAVE_RECV, mochiweb_request_recv). +-define(SAVE_BODY, mochiweb_request_body). +-define(SAVE_BODY_LENGTH, mochiweb_request_body_length). +-define(SAVE_POST, mochiweb_request_post). +-define(SAVE_COOKIE, mochiweb_request_cookie). +-define(SAVE_FORCE_CLOSE, mochiweb_request_force_close). + +%% @type key() = atom() | string() | binary() +%% @type value() = atom() | string() | binary() | integer() +%% @type headers(). A mochiweb_headers structure. +%% @type request(). A mochiweb_request parameterized module instance. +%% @type response(). A mochiweb_response parameterized module instance. +%% @type ioheaders() = headers() | [{key(), value()}]. + +% 5 minute default idle timeout +-define(IDLE_TIMEOUT, 300000). + +% Maximum recv_body() length of 1MB +-define(MAX_RECV_BODY, (1024*1024)). + +%% @spec new(Socket, Method, RawPath, Version, headers()) -> request() +%% @doc Create a new request instance. +new(Socket, Method, RawPath, Version, Headers) -> + new(Socket, [], Method, RawPath, Version, Headers). + +%% @spec new(Socket, Opts, Method, RawPath, Version, headers()) -> request() +%% @doc Create a new request instance. +new(Socket, Opts, Method, RawPath, Version, Headers) -> + {?MODULE, [Socket, Opts, Method, RawPath, Version, Headers]}. + +%% @spec get_header_value(K, request()) -> undefined | Value +%% @doc Get the value of a given request header. +get_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) -> + mochiweb_headers:get_value(K, Headers). + +get_primary_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) -> + mochiweb_headers:get_primary_value(K, Headers). + +get_combined_header_value(K, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) -> + mochiweb_headers:get_combined_value(K, Headers). + +%% @type field() = socket | scheme | method | raw_path | version | headers | peer | path | body_length | range + +%% @spec get(field(), request()) -> term() +%% @doc Return the internal representation of the given field. If +%% socket is requested on a HTTPS connection, then +%% an ssl socket will be returned as {ssl, SslSocket}. +%% You can use SslSocket with the ssl +%% application, eg: ssl:peercert(SslSocket). +get(socket, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + Socket; +get(scheme, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + case mochiweb_socket:type(Socket) of + plain -> + http; + ssl -> + https + end; +get(method, {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}) -> + Method; +get(raw_path, {?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) -> + RawPath; +get(version, {?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}) -> + Version; +get(headers, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}) -> + Headers; +get(peer, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case mochiweb_socket:peername(Socket) of + {ok, {Addr={10, _, _, _}, _Port}} -> + case get_header_value("x-forwarded-for", THIS) of + undefined -> + inet_parse:ntoa(Addr); + Hosts -> + string:strip(lists:last(string:tokens(Hosts, ","))) + end; + {ok, {{127, 0, 0, 1}, _Port}} -> + case get_header_value("x-forwarded-for", THIS) of + undefined -> + "127.0.0.1"; + Hosts -> + string:strip(lists:last(string:tokens(Hosts, ","))) + end; + {ok, {Addr, _Port}} -> + inet_parse:ntoa(Addr); + {error, enotconn} -> + exit(normal) + end; +get(path, {?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) -> + case erlang:get(?SAVE_PATH) of + undefined -> + {Path0, _, _} = mochiweb_util:urlsplit_path(RawPath), + Path = mochiweb_util:unquote(Path0), + put(?SAVE_PATH, Path), + Path; + Cached -> + Cached + end; +get(body_length, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case erlang:get(?SAVE_BODY_LENGTH) of + undefined -> + BodyLength = body_length(THIS), + put(?SAVE_BODY_LENGTH, {cached, BodyLength}), + BodyLength; + {cached, Cached} -> + Cached + end; +get(range, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case get_header_value(range, THIS) of + undefined -> + undefined; + RawRange -> + mochiweb_http:parse_range_request(RawRange) + end; +get(opts, {?MODULE, [_Socket, Opts, _Method, _RawPath, _Version, _Headers]}) -> + Opts. + +%% @spec dump(request()) -> {mochiweb_request, [{atom(), term()}]} +%% @doc Dump the internal representation to a "human readable" set of terms +%% for debugging/inspection purposes. +dump({?MODULE, [_Socket, Opts, Method, RawPath, Version, Headers]}) -> + {?MODULE, [{method, Method}, + {version, Version}, + {raw_path, RawPath}, + {opts, Opts}, + {headers, mochiweb_headers:to_list(Headers)}]}. + +%% @spec send(iodata(), request()) -> ok +%% @doc Send data over the socket. +send(Data, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + case mochiweb_socket:send(Socket, Data) of + ok -> + ok; + _ -> + exit(normal) + end. + +%% @spec recv(integer(), request()) -> binary() +%% @doc Receive Length bytes from the client as a binary, with the default +%% idle timeout. +recv(Length, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + recv(Length, ?IDLE_TIMEOUT, THIS). + +%% @spec recv(integer(), integer(), request()) -> binary() +%% @doc Receive Length bytes from the client as a binary, with the given +%% Timeout in msec. +recv(Length, Timeout, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + case mochiweb_socket:recv(Socket, Length, Timeout) of + {ok, Data} -> + put(?SAVE_RECV, true), + Data; + _ -> + exit(normal) + end. + +%% @spec body_length(request()) -> undefined | chunked | unknown_transfer_encoding | integer() +%% @doc Infer body length from transfer-encoding and content-length headers. +body_length({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case get_header_value("transfer-encoding", THIS) of + undefined -> + case get_combined_header_value("content-length", THIS) of + undefined -> + undefined; + Length -> + list_to_integer(Length) + end; + "chunked" -> + chunked; + Unknown -> + {unknown_transfer_encoding, Unknown} + end. + + +%% @spec recv_body(request()) -> binary() +%% @doc Receive the body of the HTTP request (defined by Content-Length). +%% Will only receive up to the default max-body length of 1MB. +recv_body({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + recv_body(?MAX_RECV_BODY, THIS). + +%% @spec recv_body(integer(), request()) -> binary() +%% @doc Receive the body of the HTTP request (defined by Content-Length). +%% Will receive up to MaxBody bytes. +recv_body(MaxBody, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case erlang:get(?SAVE_BODY) of + undefined -> + % we could use a sane constant for max chunk size + Body = stream_body(?MAX_RECV_BODY, fun + ({0, _ChunkedFooter}, {_LengthAcc, BinAcc}) -> + iolist_to_binary(lists:reverse(BinAcc)); + ({Length, Bin}, {LengthAcc, BinAcc}) -> + NewLength = Length + LengthAcc, + if NewLength > MaxBody -> + exit({body_too_large, chunked}); + true -> + {NewLength, [Bin | BinAcc]} + end + end, {0, []}, MaxBody, THIS), + put(?SAVE_BODY, Body), + Body; + Cached -> Cached + end. + +stream_body(MaxChunkSize, ChunkFun, FunState, {?MODULE,[_Socket,_Opts,_Method,_RawPath,_Version,_Headers]}=THIS) -> + stream_body(MaxChunkSize, ChunkFun, FunState, undefined, THIS). + +stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + Expect = case get_header_value("expect", THIS) of + undefined -> + undefined; + Value when is_list(Value) -> + string:to_lower(Value) + end, + case Expect of + "100-continue" -> + _ = start_raw_response({100, gb_trees:empty()}, THIS), + ok; + _Else -> + ok + end, + case body_length(THIS) of + undefined -> + undefined; + {unknown_transfer_encoding, Unknown} -> + exit({unknown_transfer_encoding, Unknown}); + chunked -> + % In this case the MaxBody is actually used to + % determine the maximum allowed size of a single + % chunk. + stream_chunked_body(MaxChunkSize, ChunkFun, FunState, THIS); + 0 -> + <<>>; + Length when is_integer(Length) -> + case MaxBodyLength of + MaxBodyLength when is_integer(MaxBodyLength), MaxBodyLength < Length -> + exit({body_too_large, content_length}); + _ -> + stream_unchunked_body(MaxChunkSize,Length, ChunkFun, FunState, THIS) + end + end. + + +%% @spec start_response({integer(), ioheaders()}, request()) -> response() +%% @doc Start the HTTP response by sending the Code HTTP response and +%% ResponseHeaders. The server will set header defaults such as Server +%% and Date if not present in ResponseHeaders. +start_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + start_raw_response({Code, ResponseHeaders}, THIS). + +%% @spec start_raw_response({integer(), headers()}, request()) -> response() +%% @doc Start the HTTP response by sending the Code HTTP response and +%% ResponseHeaders. +start_raw_response({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + {Header, Response} = format_response_header({Code, ResponseHeaders}, THIS), + send(Header, THIS), + Response. + + +%% @spec start_response_length({integer(), ioheaders(), integer()}, request()) -> response() +%% @doc Start the HTTP response by sending the Code HTTP response and +%% ResponseHeaders including a Content-Length of Length. The server +%% will set header defaults such as Server +%% and Date if not present in ResponseHeaders. +start_response_length({Code, ResponseHeaders, Length}, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + HResponse = mochiweb_headers:make(ResponseHeaders), + HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse), + start_response({Code, HResponse1}, THIS). + +%% @spec format_response_header({integer(), ioheaders()} | {integer(), ioheaders(), integer()}, request()) -> iolist() +%% @doc Format the HTTP response header, including the Code HTTP response and +%% ResponseHeaders including an optional Content-Length of Length. The server +%% will set header defaults such as Server +%% and Date if not present in ResponseHeaders. +format_response_header({Code, ResponseHeaders}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}=THIS) -> + HResponse = mochiweb_headers:make(ResponseHeaders), + HResponse1 = mochiweb_headers:default_from_list(server_headers(), HResponse), + HResponse2 = case should_close(THIS) of + true -> + mochiweb_headers:enter("Connection", "close", HResponse1); + false -> + HResponse1 + end, + End = [[mochiweb_util:make_io(K), <<": ">>, V, <<"\r\n">>] + || {K, V} <- mochiweb_headers:to_list(HResponse2)], + Response = mochiweb:new_response({THIS, Code, HResponse2}), + {[make_version(Version), make_code(Code), <<"\r\n">> | [End, <<"\r\n">>]], Response}; +format_response_header({Code, ResponseHeaders, Length}, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + HResponse = mochiweb_headers:make(ResponseHeaders), + HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse), + format_response_header({Code, HResponse1}, THIS). + +%% @spec respond({integer(), ioheaders(), iodata() | chunked | {file, IoDevice}}, request()) -> response() +%% @doc Start the HTTP response with start_response, and send Body to the +%% client (if the get(method) /= 'HEAD'). The Content-Length header +%% will be set by the Body length, and the server will insert header +%% defaults. +respond({Code, ResponseHeaders, {file, IoDevice}}, + {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}=THIS) -> + Length = mochiweb_io:iodevice_size(IoDevice), + Response = start_response_length({Code, ResponseHeaders, Length}, THIS), + case Method of + 'HEAD' -> + ok; + _ -> + mochiweb_io:iodevice_stream( + fun (Body) -> send(Body, THIS) end, + IoDevice) + end, + Response; +respond({Code, ResponseHeaders, chunked}, {?MODULE, [_Socket, _Opts, Method, _RawPath, Version, _Headers]}=THIS) -> + HResponse = mochiweb_headers:make(ResponseHeaders), + HResponse1 = case Method of + 'HEAD' -> + %% This is what Google does, http://www.google.com/ + %% is chunked but HEAD gets Content-Length: 0. + %% The RFC is ambiguous so emulating Google is smart. + mochiweb_headers:enter("Content-Length", "0", + HResponse); + _ when Version >= {1, 1} -> + %% Only use chunked encoding for HTTP/1.1 + mochiweb_headers:enter("Transfer-Encoding", "chunked", + HResponse); + _ -> + %% For pre-1.1 clients we send the data as-is + %% without a Content-Length header and without + %% chunk delimiters. Since the end of the document + %% is now ambiguous we must force a close. + put(?SAVE_FORCE_CLOSE, true), + HResponse + end, + start_response({Code, HResponse1}, THIS); +respond({Code, ResponseHeaders, Body}, {?MODULE, [_Socket, _Opts, Method, _RawPath, _Version, _Headers]}=THIS) -> + {Header, Response} = format_response_header({Code, ResponseHeaders, iolist_size(Body)}, THIS), + case Method of + 'HEAD' -> send(Header, THIS); + _ -> send([Header, Body], THIS) + end, + Response. + +%% @spec not_found(request()) -> response() +%% @doc Alias for not_found([]). +not_found({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + not_found([], THIS). + +%% @spec not_found(ExtraHeaders, request()) -> response() +%% @doc Alias for respond({404, [{"Content-Type", "text/plain"} +%% | ExtraHeaders], <<"Not found.">>}). +not_found(ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + respond({404, [{"Content-Type", "text/plain"} | ExtraHeaders], + <<"Not found.">>}, THIS). + +%% @spec ok({value(), iodata()} | {value(), ioheaders(), iodata() | {file, IoDevice}}, request()) -> +%% response() +%% @doc respond({200, [{"Content-Type", ContentType} | Headers], Body}). +ok({ContentType, Body}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + ok({ContentType, [], Body}, THIS); +ok({ContentType, ResponseHeaders, Body}, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + HResponse = mochiweb_headers:make(ResponseHeaders), + case THIS:get(range) of + X when (X =:= undefined orelse X =:= fail) orelse Body =:= chunked -> + %% http://code.google.com/p/mochiweb/issues/detail?id=54 + %% Range header not supported when chunked, return 200 and provide + %% full response. + HResponse1 = mochiweb_headers:enter("Content-Type", ContentType, + HResponse), + respond({200, HResponse1, Body}, THIS); + Ranges -> + {PartList, Size} = range_parts(Body, Ranges), + case PartList of + [] -> %% no valid ranges + HResponse1 = mochiweb_headers:enter("Content-Type", + ContentType, + HResponse), + %% could be 416, for now we'll just return 200 + respond({200, HResponse1, Body}, THIS); + PartList -> + {RangeHeaders, RangeBody} = + mochiweb_multipart:parts_to_body(PartList, ContentType, Size), + HResponse1 = mochiweb_headers:enter_from_list( + [{"Accept-Ranges", "bytes"} | + RangeHeaders], + HResponse), + respond({206, HResponse1, RangeBody}, THIS) + end + end. + +%% @spec should_close(request()) -> bool() +%% @doc Return true if the connection must be closed. If false, using +%% Keep-Alive should be safe. +should_close({?MODULE, [_Socket, _Opts, _Method, _RawPath, Version, _Headers]}=THIS) -> + ForceClose = erlang:get(?SAVE_FORCE_CLOSE) =/= undefined, + DidNotRecv = erlang:get(?SAVE_RECV) =:= undefined, + ForceClose orelse Version < {1, 0} + %% Connection: close + orelse is_close(get_header_value("connection", THIS)) + %% HTTP 1.0 requires Connection: Keep-Alive + orelse (Version =:= {1, 0} + andalso get_header_value("connection", THIS) =/= "Keep-Alive") + %% unread data left on the socket, can't safely continue + orelse (DidNotRecv + andalso get_combined_header_value("content-length", THIS) =/= undefined + andalso list_to_integer(get_combined_header_value("content-length", THIS)) > 0) + orelse (DidNotRecv + andalso get_header_value("transfer-encoding", THIS) =:= "chunked"). + +is_close("close") -> + true; +is_close(S=[_C, _L, _O, _S, _E]) -> + string:to_lower(S) =:= "close"; +is_close(_) -> + false. + +%% @spec cleanup(request()) -> ok +%% @doc Clean up any junk in the process dictionary, required before continuing +%% a Keep-Alive request. +cleanup({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + L = [?SAVE_QS, ?SAVE_PATH, ?SAVE_RECV, ?SAVE_BODY, ?SAVE_BODY_LENGTH, + ?SAVE_POST, ?SAVE_COOKIE, ?SAVE_FORCE_CLOSE], + lists:foreach(fun(K) -> + erase(K) + end, L), + ok. + +%% @spec parse_qs(request()) -> [{Key::string(), Value::string()}] +%% @doc Parse the query string of the URL. +parse_qs({?MODULE, [_Socket, _Opts, _Method, RawPath, _Version, _Headers]}) -> + case erlang:get(?SAVE_QS) of + undefined -> + {_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath), + Parsed = mochiweb_util:parse_qs(QueryString), + put(?SAVE_QS, Parsed), + Parsed; + Cached -> + Cached + end. + +%% @spec get_cookie_value(Key::string, request()) -> string() | undefined +%% @doc Get the value of the given cookie. +get_cookie_value(Key, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + proplists:get_value(Key, parse_cookie(THIS)). + +%% @spec parse_cookie(request()) -> [{Key::string(), Value::string()}] +%% @doc Parse the cookie header. +parse_cookie({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case erlang:get(?SAVE_COOKIE) of + undefined -> + Cookies = case get_header_value("cookie", THIS) of + undefined -> + []; + Value -> + mochiweb_cookies:parse_cookie(Value) + end, + put(?SAVE_COOKIE, Cookies), + Cookies; + Cached -> + Cached + end. + +%% @spec parse_post(request()) -> [{Key::string(), Value::string()}] +%% @doc Parse an application/x-www-form-urlencoded form POST. This +%% has the side-effect of calling recv_body(). +parse_post({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case erlang:get(?SAVE_POST) of + undefined -> + Parsed = case recv_body(THIS) of + undefined -> + []; + Binary -> + case get_primary_header_value("content-type",THIS) of + "application/x-www-form-urlencoded" ++ _ -> + mochiweb_util:parse_qs(Binary); + _ -> + [] + end + end, + put(?SAVE_POST, Parsed), + Parsed; + Cached -> + Cached + end. + +%% @spec stream_chunked_body(integer(), fun(), term(), request()) -> term() +%% @doc The function is called for each chunk. +%% Used internally by read_chunked_body. +stream_chunked_body(MaxChunkSize, Fun, FunState, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case read_chunk_length(THIS) of + 0 -> + Fun({0, read_chunk(0, THIS)}, FunState); + Length when Length > MaxChunkSize -> + NewState = read_sub_chunks(Length, MaxChunkSize, Fun, FunState, THIS), + stream_chunked_body(MaxChunkSize, Fun, NewState, THIS); + Length -> + NewState = Fun({Length, read_chunk(Length, THIS)}, FunState), + stream_chunked_body(MaxChunkSize, Fun, NewState, THIS) + end. + +stream_unchunked_body(_MaxChunkSize, 0, Fun, FunState, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + Fun({0, <<>>}, FunState); +stream_unchunked_body(MaxChunkSize, Length, Fun, FunState, + {?MODULE, [_Socket, Opts, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > 0 -> + RecBuf = case mochilists:get_value(recbuf, Opts, ?RECBUF_SIZE) of + undefined -> %os controlled buffer size + MaxChunkSize; + Val -> + Val + end, + PktSize=min(Length,RecBuf), + Bin = recv(PktSize, THIS), + NewState = Fun({PktSize, Bin}, FunState), + stream_unchunked_body(MaxChunkSize, Length - PktSize, Fun, NewState, THIS). + +%% @spec read_chunk_length(request()) -> integer() +%% @doc Read the length of the next HTTP chunk. +read_chunk_length({?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, line}])), + case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of + {ok, Header} -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, raw}])), + Splitter = fun (C) -> + C =/= $\r andalso C =/= $\n andalso C =/= $ + end, + {Hex, _Rest} = lists:splitwith(Splitter, binary_to_list(Header)), + mochihex:to_int(Hex); + _ -> + exit(normal) + end. + +%% @spec read_chunk(integer(), request()) -> Chunk::binary() | [Footer::binary()] +%% @doc Read in a HTTP chunk of the given length. If Length is 0, then read the +%% HTTP footers (as a list of binaries, since they're nominal). +read_chunk(0, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, line}])), + F = fun (F1, Acc) -> + case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of + {ok, <<"\r\n">>} -> + Acc; + {ok, Footer} -> + F1(F1, [Footer | Acc]); + _ -> + exit(normal) + end + end, + Footers = F(F, []), + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, raw}])), + put(?SAVE_RECV, true), + Footers; +read_chunk(Length, {?MODULE, [Socket, _Opts, _Method, _RawPath, _Version, _Headers]}) -> + case mochiweb_socket:recv(Socket, 2 + Length, ?IDLE_TIMEOUT) of + {ok, <>} -> + Chunk; + _ -> + exit(normal) + end. + +read_sub_chunks(Length, MaxChunkSize, Fun, FunState, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) when Length > MaxChunkSize -> + Bin = recv(MaxChunkSize, THIS), + NewState = Fun({size(Bin), Bin}, FunState), + read_sub_chunks(Length - MaxChunkSize, MaxChunkSize, Fun, NewState, THIS); + +read_sub_chunks(Length, _MaxChunkSize, Fun, FunState, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + Fun({Length, read_chunk(Length, THIS)}, FunState). + +%% @spec serve_file(Path, DocRoot, request()) -> Response +%% @doc Serve a file relative to DocRoot. +serve_file(Path, DocRoot, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + serve_file(Path, DocRoot, [], THIS). + +%% @spec serve_file(Path, DocRoot, ExtraHeaders, request()) -> Response +%% @doc Serve a file relative to DocRoot. +serve_file(Path, DocRoot, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case mochiweb_util:safe_relative_path(Path) of + undefined -> + not_found(ExtraHeaders, THIS); + RelPath -> + FullPath = filename:join([DocRoot, RelPath]), + case filelib:is_dir(FullPath) of + true -> + maybe_redirect(RelPath, FullPath, ExtraHeaders, THIS); + false -> + maybe_serve_file(FullPath, ExtraHeaders, THIS) + end + end. + +%% Internal API + +%% This has the same effect as the DirectoryIndex directive in httpd +directory_index(FullPath) -> + filename:join([FullPath, "index.html"]). + +maybe_redirect([], FullPath, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS); + +maybe_redirect(RelPath, FullPath, ExtraHeaders, + {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, Headers]}=THIS) -> + case string:right(RelPath, 1) of + "/" -> + maybe_serve_file(directory_index(FullPath), ExtraHeaders, THIS); + _ -> + Host = mochiweb_headers:get_value("host", Headers), + Location = "http://" ++ Host ++ "/" ++ RelPath ++ "/", + LocationBin = list_to_binary(Location), + MoreHeaders = [{"Location", Location}, + {"Content-Type", "text/html"} | ExtraHeaders], + Top = <<"" + "" + "301 Moved Permanently" + "" + "

Moved Permanently

" + "

The document has moved >, + Bottom = <<">here.

\n">>, + Body = <>, + respond({301, MoreHeaders, Body}, THIS) + end. + +maybe_serve_file(File, ExtraHeaders, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case file:read_file_info(File) of + {ok, FileInfo} -> + LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime), + case get_header_value("if-modified-since", THIS) of + LastModified -> + respond({304, ExtraHeaders, ""}, THIS); + _ -> + case file:open(File, [raw, binary]) of + {ok, IoDevice} -> + ContentType = mochiweb_util:guess_mime(File), + Res = ok({ContentType, + [{"last-modified", LastModified} + | ExtraHeaders], + {file, IoDevice}}, THIS), + ok = file:close(IoDevice), + Res; + _ -> + not_found(ExtraHeaders, THIS) + end + end; + {error, _} -> + not_found(ExtraHeaders, THIS) + end. + +server_headers() -> + [{"Server", "MochiWeb/1.0 (" ++ ?QUIP ++ ")"}, + {"Date", mochiweb_clock:rfc1123()}]. + +make_code(X) when is_integer(X) -> + [integer_to_list(X), [" " | httpd_util:reason_phrase(X)]]; +make_code(Io) when is_list(Io); is_binary(Io) -> + Io. + +make_version({1, 0}) -> + <<"HTTP/1.0 ">>; +make_version(_) -> + <<"HTTP/1.1 ">>. + +range_parts({file, IoDevice}, Ranges) -> + Size = mochiweb_io:iodevice_size(IoDevice), + F = fun (Spec, Acc) -> + case mochiweb_http:range_skip_length(Spec, Size) of + invalid_range -> + Acc; + V -> + [V | Acc] + end + end, + LocNums = lists:foldr(F, [], Ranges), + {ok, Data} = file:pread(IoDevice, LocNums), + Bodies = lists:zipwith(fun ({Skip, Length}, PartialBody) -> + case Length of + 0 -> + {Skip, Skip, <<>>}; + _ -> + {Skip, Skip + Length - 1, PartialBody} + end + end, + LocNums, Data), + {Bodies, Size}; +range_parts(Body0, Ranges) -> + Body = iolist_to_binary(Body0), + Size = size(Body), + F = fun(Spec, Acc) -> + case mochiweb_http:range_skip_length(Spec, Size) of + invalid_range -> + Acc; + {Skip, Length} -> + <<_:Skip/binary, PartialBody:Length/binary, _/binary>> = Body, + [{Skip, Skip + Length - 1, PartialBody} | Acc] + end + end, + {lists:foldr(F, [], Ranges), Size}. + +%% @spec accepted_encodings([encoding()], request()) -> [encoding()] | bad_accept_encoding_value +%% @type encoding() = string(). +%% +%% @doc Returns a list of encodings accepted by a request. Encodings that are +%% not supported by the server will not be included in the return list. +%% This list is computed from the "Accept-Encoding" header and +%% its elements are ordered, descendingly, according to their Q values. +%% +%% Section 14.3 of the RFC 2616 (HTTP 1.1) describes the "Accept-Encoding" +%% header and the process of determining which server supported encodings +%% can be used for encoding the body for the request's response. +%% +%% Examples +%% +%% 1) For a missing "Accept-Encoding" header: +%% accepted_encodings(["gzip", "identity"]) -> ["identity"] +%% +%% 2) For an "Accept-Encoding" header with value "gzip, deflate": +%% accepted_encodings(["gzip", "identity"]) -> ["gzip", "identity"] +%% +%% 3) For an "Accept-Encoding" header with value "gzip;q=0.5, deflate": +%% accepted_encodings(["gzip", "deflate", "identity"]) -> +%% ["deflate", "gzip", "identity"] +%% +accepted_encodings(SupportedEncodings, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + AcceptEncodingHeader = case get_header_value("Accept-Encoding", THIS) of + undefined -> + ""; + Value -> + Value + end, + case mochiweb_util:parse_qvalues(AcceptEncodingHeader) of + invalid_qvalue_string -> + bad_accept_encoding_value; + QList -> + mochiweb_util:pick_accepted_encodings( + QList, SupportedEncodings, "identity" + ) + end. + +%% @spec accepts_content_type(string() | binary(), request()) -> boolean() | bad_accept_header +%% +%% @doc Determines whether a request accepts a given media type by analyzing its +%% "Accept" header. +%% +%% Examples +%% +%% 1) For a missing "Accept" header: +%% accepts_content_type("application/json") -> true +%% +%% 2) For an "Accept" header with value "text/plain, application/*": +%% accepts_content_type("application/json") -> true +%% +%% 3) For an "Accept" header with value "text/plain, */*; q=0.0": +%% accepts_content_type("application/json") -> false +%% +%% 4) For an "Accept" header with value "text/plain; q=0.5, */*; q=0.1": +%% accepts_content_type("application/json") -> true +%% +%% 5) For an "Accept" header with value "text/*; q=0.0, */*": +%% accepts_content_type("text/plain") -> false +%% +accepts_content_type(ContentType1, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + ContentType = re:replace(ContentType1, "\\s", "", [global, {return, list}]), + AcceptHeader = accept_header(THIS), + case mochiweb_util:parse_qvalues(AcceptHeader) of + invalid_qvalue_string -> + bad_accept_header; + QList -> + [MainType, _SubType] = string:tokens(ContentType, "/"), + SuperType = MainType ++ "/*", + lists:any( + fun({"*/*", Q}) when Q > 0.0 -> + true; + ({Type, Q}) when Q > 0.0 -> + Type =:= ContentType orelse Type =:= SuperType; + (_) -> + false + end, + QList + ) andalso + (not lists:member({ContentType, 0.0}, QList)) andalso + (not lists:member({SuperType, 0.0}, QList)) + end. + +%% @spec accepted_content_types([string() | binary()], request()) -> [string()] | bad_accept_header +%% +%% @doc Filters which of the given media types this request accepts. This filtering +%% is performed by analyzing the "Accept" header. The returned list is sorted +%% according to the preferences specified in the "Accept" header (higher Q values +%% first). If two or more types have the same preference (Q value), they're order +%% in the returned list is the same as they're order in the input list. +%% +%% Examples +%% +%% 1) For a missing "Accept" header: +%% accepted_content_types(["text/html", "application/json"]) -> +%% ["text/html", "application/json"] +%% +%% 2) For an "Accept" header with value "text/html, application/*": +%% accepted_content_types(["application/json", "text/html"]) -> +%% ["application/json", "text/html"] +%% +%% 3) For an "Accept" header with value "text/html, */*; q=0.0": +%% accepted_content_types(["text/html", "application/json"]) -> +%% ["text/html"] +%% +%% 4) For an "Accept" header with value "text/html; q=0.5, */*; q=0.1": +%% accepts_content_types(["application/json", "text/html"]) -> +%% ["text/html", "application/json"] +%% +accepted_content_types(Types1, {?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + Types = lists:map( + fun(T) -> re:replace(T, "\\s", "", [global, {return, list}]) end, + Types1), + AcceptHeader = accept_header(THIS), + case mochiweb_util:parse_qvalues(AcceptHeader) of + invalid_qvalue_string -> + bad_accept_header; + QList -> + TypesQ = lists:foldr( + fun(T, Acc) -> + case proplists:get_value(T, QList) of + undefined -> + [MainType, _SubType] = string:tokens(T, "/"), + case proplists:get_value(MainType ++ "/*", QList) of + undefined -> + case proplists:get_value("*/*", QList) of + Q when is_float(Q), Q > 0.0 -> + [{Q, T} | Acc]; + _ -> + Acc + end; + Q when Q > 0.0 -> + [{Q, T} | Acc]; + _ -> + Acc + end; + Q when Q > 0.0 -> + [{Q, T} | Acc]; + _ -> + Acc + end + end, + [], Types), + % Note: Stable sort. If 2 types have the same Q value we leave them in the + % same order as in the input list. + SortFun = fun({Q1, _}, {Q2, _}) -> Q1 >= Q2 end, + [Type || {_Q, Type} <- lists:sort(SortFun, TypesQ)] + end. + +accept_header({?MODULE, [_Socket, _Opts, _Method, _RawPath, _Version, _Headers]}=THIS) -> + case get_header_value("Accept", THIS) of + undefined -> + "*/*"; + Value -> + Value + end. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochiweb_response.erl b/deps/mochiweb/src/mochiweb_response.erl new file mode 100644 index 0000000..195e652 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_response.erl @@ -0,0 +1,90 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Response abstraction. + +-module(mochiweb_response). +-author('bob@mochimedia.com'). + +-define(QUIP, "Any of you quaids got a smint?"). + +-export([new/3, get_header_value/2, get/2, dump/1]). +-export([send/2, write_chunk/2]). + +%% @type response(). A mochiweb_response parameterized module instance. + +%% @spec new(Request, Code, Headers) -> response() +%% @doc Create a new mochiweb_response instance. +new(Request, Code, Headers) -> + {?MODULE, [Request, Code, Headers]}. + +%% @spec get_header_value(string() | atom() | binary(), response()) -> +%% string() | undefined +%% @doc Get the value of the given response header. +get_header_value(K, {?MODULE, [_Request, _Code, Headers]}) -> + mochiweb_headers:get_value(K, Headers). + +%% @spec get(request | code | headers, response()) -> term() +%% @doc Return the internal representation of the given field. +get(request, {?MODULE, [Request, _Code, _Headers]}) -> + Request; +get(code, {?MODULE, [_Request, Code, _Headers]}) -> + Code; +get(headers, {?MODULE, [_Request, _Code, Headers]}) -> + Headers. + +%% @spec dump(response()) -> {mochiweb_request, [{atom(), term()}]} +%% @doc Dump the internal representation to a "human readable" set of terms +%% for debugging/inspection purposes. +dump({?MODULE, [Request, Code, Headers]}) -> + [{request, Request:dump()}, + {code, Code}, + {headers, mochiweb_headers:to_list(Headers)}]. + +%% @spec send(iodata(), response()) -> ok +%% @doc Send data over the socket if the method is not HEAD. +send(Data, {?MODULE, [Request, _Code, _Headers]}) -> + case Request:get(method) of + 'HEAD' -> + ok; + _ -> + Request:send(Data) + end. + +%% @spec write_chunk(iodata(), response()) -> ok +%% @doc Write a chunk of a HTTP chunked response. If Data is zero length, +%% then the chunked response will be finished. +write_chunk(Data, {?MODULE, [Request, _Code, _Headers]}=THIS) -> + case Request:get(version) of + Version when Version >= {1, 1} -> + Length = iolist_size(Data), + send([io_lib:format("~.16b\r\n", [Length]), Data, <<"\r\n">>], THIS); + _ -> + send(Data, THIS) + end. + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/src/mochiweb_session.erl b/deps/mochiweb/src/mochiweb_session.erl new file mode 100644 index 0000000..c9f88e2 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_session.erl @@ -0,0 +1,229 @@ +%% @author Asier Azkuenaga Batiz +%% @copyright 2013 Mochi Media, Inc. +%% +%% 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. + +%% @doc HTTP Cookie session. Note that the expiration time travels unencrypted +%% as far as this module is concerned. In order to achieve more security, +%% it is advised to use https. +%% Based on the paper +%% +%% "A Secure Cookie Protocol". +%% This module is only supported on R15B02 and later, the AES CFB mode is not +%% available in earlier releases of crypto. +-module(mochiweb_session). +-export([generate_session_data/4, generate_session_cookie/4, + check_session_cookie/4]). + +-export_types([expiration_time/0]). +-type expiration_time() :: integer(). +-type key_fun() :: fun((string()) -> iolist()). + +%% TODO: Import this from elsewhere after attribute types refactor. +-type header() :: {string(), string()}. + +%% @doc Generates a secure encrypted binary convining all the parameters. The +%% expiration time must be a 32-bit integer. +-spec generate_session_data( + ExpirationTime :: expiration_time(), + Data :: iolist(), + FSessionKey :: key_fun(), + ServerKey :: iolist()) -> binary(). +generate_session_data(ExpirationTime, Data, FSessionKey, ServerKey) + when is_integer(ExpirationTime), is_function(FSessionKey)-> + BData = ensure_binary(Data), + ExpTime = integer_to_list(ExpirationTime), + Key = gen_key(ExpTime, ServerKey), + Hmac = gen_hmac(ExpTime, BData, FSessionKey(ExpTime), Key), + EData = encrypt_data(BData, Key), + mochiweb_base64url:encode( + <>). + +%% @doc Convenience wrapper for generate_session_data that returns a +%% mochiweb cookie with "id" as the key, a max_age of 20000 seconds, +%% and the current local time as local time. +-spec generate_session_cookie( + ExpirationTime :: expiration_time(), + Data :: iolist(), + FSessionKey :: key_fun(), + ServerKey :: iolist()) -> header(). +generate_session_cookie(ExpirationTime, Data, FSessionKey, ServerKey) + when is_integer(ExpirationTime), is_function(FSessionKey)-> + CookieData = generate_session_data(ExpirationTime, Data, + FSessionKey, ServerKey), + mochiweb_cookies:cookie("id", CookieData, + [{max_age, 20000}, + {local_time, + calendar:universal_time_to_local_time( + calendar:universal_time())}]). + +%% TODO: This return type is messy to express in the type system. +-spec check_session_cookie( + ECookie :: binary(), + ExpirationTime :: string(), + FSessionKey :: key_fun(), + ServerKey :: iolist()) -> + {Success :: boolean(), + ExpTimeAndData :: [integer() | binary()]}. +check_session_cookie(ECookie, ExpirationTime, FSessionKey, ServerKey) + when is_binary(ECookie), is_integer(ExpirationTime), + is_function(FSessionKey) -> + case mochiweb_base64url:decode(ECookie) of + <> -> + ETString = integer_to_list(ExpirationTime1), + Key = gen_key(ETString, ServerKey), + Data = decrypt_data(EData, Key), + Hmac2 = gen_hmac(ETString, + Data, + FSessionKey(ETString), + Key), + {ExpirationTime1 >= ExpirationTime andalso eq(Hmac2, BHmac), + [ExpirationTime1, binary_to_list(Data)]}; + _ -> + {false, []} + end; +check_session_cookie(_ECookie, _ExpirationTime, _FSessionKey, _ServerKey) -> + {false, []}. + +%% 'Constant' time =:= operator for binary, to mitigate timing attacks. +-spec eq(binary(), binary()) -> boolean(). +eq(A, B) when is_binary(A) andalso is_binary(B) -> + eq(A, B, 0). + +eq(<>, <>, Acc) -> + eq(As, Bs, Acc bor (A bxor B)); +eq(<<>>, <<>>, 0) -> + true; +eq(_As, _Bs, _Acc) -> + false. + +-spec ensure_binary(iolist()) -> binary(). +ensure_binary(B) when is_binary(B) -> + B; +ensure_binary(L) when is_list(L) -> + iolist_to_binary(L). + +-ifdef(crypto_compatibility). +-spec encrypt_data(binary(), binary()) -> binary(). +encrypt_data(Data, Key) -> + IV = crypto:rand_bytes(16), + Crypt = crypto:aes_cfb_128_encrypt(Key, IV, Data), + <>. + +-spec decrypt_data(binary(), binary()) -> binary(). +decrypt_data(<>, Key) -> + crypto:aes_cfb_128_decrypt(Key, IV, Crypt). + +-spec gen_key(iolist(), iolist()) -> binary(). +gen_key(ExpirationTime, ServerKey)-> + crypto:md5_mac(ServerKey, [ExpirationTime]). + +-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary(). +gen_hmac(ExpirationTime, Data, SessionKey, Key) -> + crypto:sha_mac(Key, [ExpirationTime, Data, SessionKey]). + +-else. +-spec encrypt_data(binary(), binary()) -> binary(). +encrypt_data(Data, Key) -> + IV = crypto:rand_bytes(16), + Crypt = crypto:block_encrypt(aes_cfb128, Key, IV, Data), + <>. + +-spec decrypt_data(binary(), binary()) -> binary(). +decrypt_data(<>, Key) -> + crypto:block_decrypt(aes_cfb128, Key, IV, Crypt). + +-spec gen_key(iolist(), iolist()) -> binary(). +gen_key(ExpirationTime, ServerKey)-> + crypto:hmac(md5, ServerKey, [ExpirationTime]). + +-spec gen_hmac(iolist(), binary(), iolist(), binary()) -> binary(). +gen_hmac(ExpirationTime, Data, SessionKey, Key) -> + crypto:hmac(sha, Key, [ExpirationTime, Data, SessionKey]). + +-endif. + +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +generate_check_session_cookie_test_() -> + {setup, + fun setup_server_key/0, + fun generate_check_session_cookie/1}. + +setup_server_key() -> + crypto:start(), + ["adfasdfasfs",30000]. + +generate_check_session_cookie([ServerKey, TS]) -> + Id = fun (A) -> A end, + TSFuture = TS + 1000, + TSPast = TS - 1, + [?_assertEqual( + {true, [TSFuture, "alice"]}, + check_session_cookie( + generate_session_data(TSFuture, "alice", Id, ServerKey), + TS, Id, ServerKey)), + ?_assertEqual( + {true, [TSFuture, "alice and"]}, + check_session_cookie( + generate_session_data(TSFuture, "alice and", Id, ServerKey), + TS, Id, ServerKey)), + ?_assertEqual( + {true, [TSFuture, "alice and"]}, + check_session_cookie( + generate_session_data(TSFuture, "alice and", Id, ServerKey), + TS, Id,ServerKey)), + ?_assertEqual( + {true, [TSFuture, "alice and bob"]}, + check_session_cookie( + generate_session_data(TSFuture, "alice and bob", + Id, ServerKey), + TS, Id, ServerKey)), + ?_assertEqual( + {true, [TSFuture, "alice jlkjfkjsdfg sdkfjgldsjgl"]}, + check_session_cookie( + generate_session_data(TSFuture, "alice jlkjfkjsdfg sdkfjgldsjgl", + Id, ServerKey), + TS, Id, ServerKey)), + ?_assertEqual( + {true, [TSFuture, "alice .'¡'ç+-$%/(&\""]}, + check_session_cookie( + generate_session_data(TSFuture, "alice .'¡'ç+-$%/(&\"" + ,Id, ServerKey), + TS, Id, ServerKey)), + ?_assertEqual( + {true,[TSFuture,"alice456689875"]}, + check_session_cookie( + generate_session_data(TSFuture, ["alice","456689875"], + Id, ServerKey), + TS, Id, ServerKey)), + ?_assertError( + function_clause, + check_session_cookie( + generate_session_data(TSFuture, {tuple,one}, + Id, ServerKey), + TS, Id,ServerKey)), + ?_assertEqual( + {false, [TSPast, "bob"]}, + check_session_cookie( + generate_session_data(TSPast, "bob", Id,ServerKey), + TS, Id, ServerKey)) + ]. +-endif. diff --git a/deps/mochiweb/src/mochiweb_socket.erl b/deps/mochiweb/src/mochiweb_socket.erl new file mode 100644 index 0000000..1756b8e --- /dev/null +++ b/deps/mochiweb/src/mochiweb_socket.erl @@ -0,0 +1,148 @@ +%% @copyright 2010 Mochi Media, Inc. + +%% @doc MochiWeb socket - wrapper for plain and ssl sockets. + +-module(mochiweb_socket). + +-export([listen/4, + accept/1, transport_accept/1, finish_accept/1, + recv/3, send/2, close/1, port/1, peername/1, + setopts/2, getopts/2, type/1, exit_if_closed/1]). + +-define(ACCEPT_TIMEOUT, 2000). +-define(SSL_TIMEOUT, 10000). +-define(SSL_HANDSHAKE_TIMEOUT, 20000). + + +listen(Ssl, Port, Opts, SslOpts) -> + case Ssl of + true -> + Opts1 = add_unbroken_ciphers_default(Opts ++ SslOpts), + Opts2 = add_safe_protocol_versions(Opts1), + case ssl:listen(Port, Opts2) of + {ok, ListenSocket} -> + {ok, {ssl, ListenSocket}}; + {error, _} = Err -> + Err + end; + false -> + gen_tcp:listen(Port, Opts) + end. + +add_unbroken_ciphers_default(Opts) -> + Default = filter_unsecure_cipher_suites(ssl:cipher_suites()), + Ciphers = filter_broken_cipher_suites(proplists:get_value(ciphers, Opts, Default)), + [{ciphers, Ciphers} | proplists:delete(ciphers, Opts)]. + +filter_broken_cipher_suites(Ciphers) -> + case proplists:get_value(ssl_app, ssl:versions()) of + "5.3" ++ _ -> + lists:filter(fun(Suite) -> + string:left(atom_to_list(element(1, Suite)), 4) =/= "ecdh" + end, Ciphers); + _ -> + Ciphers + end. + +filter_unsecure_cipher_suites(Ciphers) -> + lists:filter(fun + ({_,des_cbc,_}) -> false; + ({_,_,md5}) -> false; + (_) -> true + end, + Ciphers). + +add_safe_protocol_versions(Opts) -> + case proplists:is_defined(versions, Opts) of + true -> + Opts; + false -> + Versions = filter_unsafe_protcol_versions(proplists:get_value(available, ssl:versions())), + [{versions, Versions} | Opts] + end. + +filter_unsafe_protcol_versions(Versions) -> + lists:filter(fun + (sslv3) -> false; + (_) -> true + end, + Versions). + +%% Provided for backwards compatibility only +accept(ListenSocket) -> + case transport_accept(ListenSocket) of + {ok, Socket} -> + finish_accept(Socket); + {error, _} = Err -> + Err + end. + +transport_accept({ssl, ListenSocket}) -> + case ssl:transport_accept(ListenSocket, ?SSL_TIMEOUT) of + {ok, Socket} -> + {ok, {ssl, Socket}}; + {error, _} = Err -> + Err + end; +transport_accept(ListenSocket) -> + gen_tcp:accept(ListenSocket, ?ACCEPT_TIMEOUT). + +finish_accept({ssl, Socket}) -> + case ssl:ssl_accept(Socket, ?SSL_HANDSHAKE_TIMEOUT) of + ok -> + {ok, {ssl, Socket}}; + {error, _} = Err -> + Err + end; +finish_accept(Socket) -> + {ok, Socket}. + +recv({ssl, Socket}, Length, Timeout) -> + ssl:recv(Socket, Length, Timeout); +recv(Socket, Length, Timeout) -> + gen_tcp:recv(Socket, Length, Timeout). + +send({ssl, Socket}, Data) -> + ssl:send(Socket, Data); +send(Socket, Data) -> + gen_tcp:send(Socket, Data). + +close({ssl, Socket}) -> + ssl:close(Socket); +close(Socket) -> + gen_tcp:close(Socket). + +port({ssl, Socket}) -> + case ssl:sockname(Socket) of + {ok, {_, Port}} -> + {ok, Port}; + {error, _} = Err -> + Err + end; +port(Socket) -> + inet:port(Socket). + +peername({ssl, Socket}) -> + ssl:peername(Socket); +peername(Socket) -> + inet:peername(Socket). + +setopts({ssl, Socket}, Opts) -> + ssl:setopts(Socket, Opts); +setopts(Socket, Opts) -> + inet:setopts(Socket, Opts). + +getopts({ssl, Socket}, Opts) -> + ssl:getopts(Socket, Opts); +getopts(Socket, Opts) -> + inet:getopts(Socket, Opts). + +type({ssl, _}) -> + ssl; +type(_) -> + plain. + +exit_if_closed({error, closed}) -> + exit(normal); +exit_if_closed(Res) -> + Res. diff --git a/deps/mochiweb/src/mochiweb_socket_server.erl b/deps/mochiweb/src/mochiweb_socket_server.erl new file mode 100644 index 0000000..fd5e382 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_socket_server.erl @@ -0,0 +1,394 @@ +%% @author Bob Ippolito +%% @copyright 2007 Mochi Media, Inc. + +%% @doc MochiWeb socket server. + +-module(mochiweb_socket_server). +-author('bob@mochimedia.com'). +-behaviour(gen_server). + +-include("internal.hrl"). + +-export([start/1, start_link/1, stop/1]). +-export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3, + handle_info/2]). +-export([get/2, set/3]). + +-record(mochiweb_socket_server, + {port, + loop, + name=undefined, + max=2048, + ip=any, + listen=null, + nodelay=false, + recbuf=?RECBUF_SIZE, + backlog=128, + active_sockets=0, + acceptor_pool_size=16, + ssl=false, + ssl_opts=[{ssl_imp, new}], + acceptor_pool=sets:new(), + profile_fun=undefined}). + +-define(is_old_state(State), not is_record(State, mochiweb_socket_server)). + +start_link(Options) -> + start_server(start_link, parse_options(Options)). + +start(Options) -> + case lists:keytake(link, 1, Options) of + {value, {_Key, false}, Options1} -> + start_server(start, parse_options(Options1)); + _ -> + %% TODO: https://github.com/mochi/mochiweb/issues/58 + %% [X] Phase 1: Add new APIs (Sep 2011) + %% [_] Phase 2: Add deprecation warning + %% [_] Phase 3: Change default to {link, false} and ignore link + %% [_] Phase 4: Add deprecation warning for {link, _} option + %% [_] Phase 5: Remove support for {link, _} option + start_link(Options) + end. + +get(Name, Property) -> + gen_server:call(Name, {get, Property}). + +set(Name, profile_fun, Fun) -> + gen_server:cast(Name, {set, profile_fun, Fun}); +set(Name, Property, _Value) -> + error_logger:info_msg("?MODULE:set for ~p with ~p not implemented~n", + [Name, Property]). + +stop(Name) when is_atom(Name) orelse is_pid(Name) -> + gen_server:call(Name, stop); +stop({Scope, Name}) when Scope =:= local orelse Scope =:= global -> + stop(Name); +stop(Options) -> + State = parse_options(Options), + stop(State#mochiweb_socket_server.name). + +%% Internal API + +parse_options(State=#mochiweb_socket_server{}) -> + State; +parse_options(Options) -> + parse_options(Options, #mochiweb_socket_server{}). + +parse_options([], State=#mochiweb_socket_server{acceptor_pool_size=PoolSize, + max=Max}) -> + case Max < PoolSize of + true -> + error_logger:info_report([{warning, "max is set lower than acceptor_pool_size"}, + {max, Max}, + {acceptor_pool_size, PoolSize}]); + false -> + ok + end, + State; +parse_options([{name, L} | Rest], State) when is_list(L) -> + Name = {local, list_to_atom(L)}, + parse_options(Rest, State#mochiweb_socket_server{name=Name}); +parse_options([{name, A} | Rest], State) when A =:= undefined -> + parse_options(Rest, State#mochiweb_socket_server{name=A}); +parse_options([{name, A} | Rest], State) when is_atom(A) -> + Name = {local, A}, + parse_options(Rest, State#mochiweb_socket_server{name=Name}); +parse_options([{name, Name} | Rest], State) -> + parse_options(Rest, State#mochiweb_socket_server{name=Name}); +parse_options([{port, L} | Rest], State) when is_list(L) -> + Port = list_to_integer(L), + parse_options(Rest, State#mochiweb_socket_server{port=Port}); +parse_options([{port, Port} | Rest], State) -> + parse_options(Rest, State#mochiweb_socket_server{port=Port}); +parse_options([{ip, Ip} | Rest], State) -> + ParsedIp = case Ip of + any -> + any; + Ip when is_tuple(Ip) -> + Ip; + Ip when is_list(Ip) -> + {ok, IpTuple} = inet_parse:address(Ip), + IpTuple + end, + parse_options(Rest, State#mochiweb_socket_server{ip=ParsedIp}); +parse_options([{loop, Loop} | Rest], State) -> + parse_options(Rest, State#mochiweb_socket_server{loop=Loop}); +parse_options([{backlog, Backlog} | Rest], State) -> + parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog}); +parse_options([{nodelay, NoDelay} | Rest], State) -> + parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay}); +parse_options([{recbuf, RecBuf} | Rest], State) when is_integer(RecBuf) orelse + RecBuf == undefined -> + %% XXX: `recbuf' value which is passed to `gen_tcp' + %% and value reported by `inet:getopts(P, [recbuf])' may + %% differ. They depends on underlying OS. From linux mans: + %% + %% The kernel doubles this value (to allow space for + %% bookkeeping overhead) when it is set using setsockopt(2), + %% and this doubled value is returned by getsockopt(2). + %% + %% See: man 7 socket | grep SO_RCVBUF + %% + %% In case undefined is passed instead of the default buffer + %% size ?RECBUF_SIZE, no size is set and the OS can control it dynamically + parse_options(Rest, State#mochiweb_socket_server{recbuf=RecBuf}); +parse_options([{acceptor_pool_size, Max} | Rest], State) -> + MaxInt = ensure_int(Max), + parse_options(Rest, + State#mochiweb_socket_server{acceptor_pool_size=MaxInt}); +parse_options([{max, Max} | Rest], State) -> + MaxInt = ensure_int(Max), + parse_options(Rest, State#mochiweb_socket_server{max=MaxInt}); +parse_options([{ssl, Ssl} | Rest], State) when is_boolean(Ssl) -> + parse_options(Rest, State#mochiweb_socket_server{ssl=Ssl}); +parse_options([{ssl_opts, SslOpts} | Rest], State) when is_list(SslOpts) -> + SslOpts1 = [{ssl_imp, new} | proplists:delete(ssl_imp, SslOpts)], + parse_options(Rest, State#mochiweb_socket_server{ssl_opts=SslOpts1}); +parse_options([{profile_fun, ProfileFun} | Rest], State) when is_function(ProfileFun) -> + parse_options(Rest, State#mochiweb_socket_server{profile_fun=ProfileFun}). + + +start_server(F, State=#mochiweb_socket_server{ssl=Ssl, name=Name}) -> + ok = prep_ssl(Ssl), + case Name of + undefined -> + gen_server:F(?MODULE, State, []); + _ -> + gen_server:F(Name, ?MODULE, State, []) + end. + +prep_ssl(true) -> + ok = mochiweb:ensure_started(crypto), + ok = mochiweb:ensure_started(asn1), + ok = mochiweb:ensure_started(public_key), + ok = mochiweb:ensure_started(ssl); +prep_ssl(false) -> + ok. + +ensure_int(N) when is_integer(N) -> + N; +ensure_int(S) when is_list(S) -> + list_to_integer(S). + +ipv6_supported() -> + case (catch inet:getaddr("localhost", inet6)) of + {ok, _Addr} -> + true; + {error, _} -> + false + end. + +init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, + nodelay=NoDelay, recbuf=RecBuf}) -> + process_flag(trap_exit, true), + + BaseOpts = [binary, + {reuseaddr, true}, + {packet, 0}, + {backlog, Backlog}, + {exit_on_close, false}, + {active, false}, + {nodelay, NoDelay}], + Opts = case Ip of + any -> + case ipv6_supported() of % IPv4, and IPv6 if supported + true -> [inet, inet6 | BaseOpts]; + _ -> BaseOpts + end; + {_, _, _, _} -> % IPv4 + [inet, {ip, Ip} | BaseOpts]; + {_, _, _, _, _, _, _, _} -> % IPv6 + [inet6, {ip, Ip} | BaseOpts] + end, + OptsBuf=case RecBuf of + undefined -> + Opts; + _ -> + [{recbuf, RecBuf}|Opts] + end, + listen(Port, OptsBuf, State). + +new_acceptor_pool(State=#mochiweb_socket_server{acceptor_pool_size=Size}) -> + lists:foldl(fun (_, S) -> new_acceptor(S) end, State, lists:seq(1, Size)). + +new_acceptor(State=#mochiweb_socket_server{acceptor_pool=Pool, + recbuf=RecBuf, + loop=Loop, + listen=Listen}) -> + LoopOpts = [{recbuf, RecBuf}], + Pid = mochiweb_acceptor:start_link(self(), Listen, Loop, LoopOpts), + State#mochiweb_socket_server{ + acceptor_pool=sets:add_element(Pid, Pool)}. + +listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) -> + case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of + {ok, Listen} -> + {ok, ListenPort} = mochiweb_socket:port(Listen), + {ok, new_acceptor_pool(State#mochiweb_socket_server{ + listen=Listen, + port=ListenPort})}; + {error, Reason} -> + {stop, Reason} + end. + +do_get(port, #mochiweb_socket_server{port=Port}) -> + Port; +do_get(waiting_acceptors, #mochiweb_socket_server{acceptor_pool=Pool}) -> + sets:size(Pool); +do_get(active_sockets, #mochiweb_socket_server{active_sockets=ActiveSockets}) -> + ActiveSockets. + + +state_to_proplist(#mochiweb_socket_server{name=Name, + port=Port, + active_sockets=ActiveSockets}) -> + [{name, Name}, {port, Port}, {active_sockets, ActiveSockets}]. + +upgrade_state(State = #mochiweb_socket_server{}) -> + State; +upgrade_state({mochiweb_socket_server, Port, Loop, Name, + Max, IP, Listen, NoDelay, Backlog, ActiveSockets, + AcceptorPoolSize, SSL, SSL_opts, + AcceptorPool}) -> + #mochiweb_socket_server{port=Port, loop=Loop, name=Name, max=Max, ip=IP, + listen=Listen, nodelay=NoDelay, backlog=Backlog, + active_sockets=ActiveSockets, + acceptor_pool_size=AcceptorPoolSize, + ssl=SSL, + ssl_opts=SSL_opts, + acceptor_pool=AcceptorPool}. + +handle_call(Req, From, State) when ?is_old_state(State) -> + handle_call(Req, From, upgrade_state(State)); +handle_call({get, Property}, _From, State) -> + Res = do_get(Property, State), + {reply, Res, State}; +handle_call(stop, _From, State) -> + {stop, normal, ok, State}; +handle_call(_Message, _From, State) -> + Res = error, + {reply, Res, State}. + + +handle_cast(Req, State) when ?is_old_state(State) -> + handle_cast(Req, upgrade_state(State)); +handle_cast({accepted, Pid, Timing}, + State=#mochiweb_socket_server{active_sockets=ActiveSockets}) -> + State1 = State#mochiweb_socket_server{active_sockets=1 + ActiveSockets}, + case State#mochiweb_socket_server.profile_fun of + undefined -> + undefined; + F when is_function(F) -> + catch F([{timing, Timing} | state_to_proplist(State1)]) + end, + {noreply, recycle_acceptor(Pid, State1)}; +handle_cast({set, profile_fun, ProfileFun}, State) -> + State1 = case ProfileFun of + ProfileFun when is_function(ProfileFun); ProfileFun =:= undefined -> + State#mochiweb_socket_server{profile_fun=ProfileFun}; + _ -> + State + end, + {noreply, State1}. + + +terminate(Reason, State) when ?is_old_state(State) -> + terminate(Reason, upgrade_state(State)); +terminate(_Reason, #mochiweb_socket_server{listen=Listen}) -> + mochiweb_socket:close(Listen). + +code_change(_OldVsn, State, _Extra) -> + State. + +recycle_acceptor(Pid, State=#mochiweb_socket_server{ + acceptor_pool=Pool, + acceptor_pool_size=PoolSize, + max=Max, + active_sockets=ActiveSockets}) -> + %% A socket is considered to be active from immediately after it + %% has been accepted (see the {accepted, Pid, Timing} cast above). + %% This function will be called when an acceptor is transitioning + %% to an active socket, or when either type of Pid dies. An acceptor + %% Pid will always be in the acceptor_pool set, and an active socket + %% will be in that set during the transition but not afterwards. + Pool1 = sets:del_element(Pid, Pool), + NewSize = sets:size(Pool1), + ActiveSockets1 = case NewSize =:= sets:size(Pool) of + %% Pid has died and it is not in the acceptor set, + %% it must be an active socket. + true -> max(0, ActiveSockets - 1); + false -> ActiveSockets + end, + State1 = State#mochiweb_socket_server{ + acceptor_pool=Pool1, + active_sockets=ActiveSockets1}, + %% Spawn a new acceptor only if it will not overrun the maximum socket + %% count or the maximum pool size. + case NewSize + ActiveSockets1 < Max andalso NewSize < PoolSize of + true -> new_acceptor(State1); + false -> State1 + end. + +handle_info(Msg, State) when ?is_old_state(State) -> + handle_info(Msg, upgrade_state(State)); +handle_info({'EXIT', Pid, normal}, State) -> + {noreply, recycle_acceptor(Pid, State)}; +handle_info({'EXIT', Pid, Reason}, + State=#mochiweb_socket_server{acceptor_pool=Pool}) -> + case sets:is_element(Pid, Pool) of + true -> + %% If there was an unexpected error accepting, log and sleep. + error_logger:error_report({?MODULE, ?LINE, + {acceptor_error, Reason}}), + timer:sleep(100); + false -> + ok + end, + {noreply, recycle_acceptor(Pid, State)}; + +% this is what release_handler needs to get a list of modules, +% since our supervisor modules list is set to 'dynamic' +% see sasl-2.1.9.2/src/release_handler_1.erl get_dynamic_mods +handle_info({From, Tag, get_modules}, State = #mochiweb_socket_server{name={local,Mod}}) -> + From ! {element(2,Tag), [Mod]}, + {noreply, State}; + +% If for some reason we can't get the module name, send empty list to avoid release_handler timeout: +handle_info({From, Tag, get_modules}, State) -> + error_logger:info_msg("mochiweb_socket_server replying to dynamic modules request as '[]'~n",[]), + From ! {element(2,Tag), []}, + {noreply, State}; + +handle_info(Info, State) -> + error_logger:info_report([{'INFO', Info}, {'State', State}]), + {noreply, State}. + + + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +upgrade_state_test() -> + OldState = {mochiweb_socket_server, + port, loop, name, + max, ip, listen, + nodelay, backlog, + active_sockets, + acceptor_pool_size, + ssl, ssl_opts, acceptor_pool}, + State = upgrade_state(OldState), + CmpState = #mochiweb_socket_server{port=port, loop=loop, + name=name, max=max, ip=ip, + listen=listen, nodelay=nodelay, + backlog=backlog, + active_sockets=active_sockets, + acceptor_pool_size=acceptor_pool_size, + ssl=ssl, ssl_opts=ssl_opts, + acceptor_pool=acceptor_pool, + profile_fun=undefined}, + ?assertEqual(CmpState, State). + +-endif. diff --git a/rabbitmq-server/deps/rabbit_common/src/mochiweb_util.erl b/deps/mochiweb/src/mochiweb_util.erl similarity index 96% rename from rabbitmq-server/deps/rabbit_common/src/mochiweb_util.erl rename to deps/mochiweb/src/mochiweb_util.erl index 9ae07f3..c606767 100644 --- a/rabbitmq-server/deps/rabbit_common/src/mochiweb_util.erl +++ b/deps/mochiweb/src/mochiweb_util.erl @@ -8,7 +8,7 @@ -export([join/2, quote_plus/1, urlencode/1, parse_qs/1, unquote/1]). -export([path_split/1]). -export([urlsplit/1, urlsplit_path/1, urlunsplit/1, urlunsplit_path/1]). --export([parse_header/1]). +-export([guess_mime/1, parse_header/1]). -export([shell_quote/1, cmd/1, cmd_string/1, cmd_port/2, cmd_status/1, cmd_status/2]). -export([record_to_proplist/2, record_to_proplist/3]). -export([safe_relative_path/1, partition/2]). @@ -354,20 +354,20 @@ urlsplit_query("#" ++ Rest, Acc) -> urlsplit_query([C | Rest], Acc) -> urlsplit_query(Rest, [C | Acc]). -% %% @spec guess_mime(string()) -> string() -% %% @doc Guess the mime type of a file by the extension of its filename. -% guess_mime(File) -> -% case filename:basename(File) of -% "crossdomain.xml" -> -% "text/x-cross-domain-policy"; -% Name -> -% case mochiweb_mime:from_extension(filename:extension(Name)) of -% undefined -> -% "text/plain"; -% Mime -> -% Mime -% end -% end. +%% @spec guess_mime(string()) -> string() +%% @doc Guess the mime type of a file by the extension of its filename. +guess_mime(File) -> + case filename:basename(File) of + "crossdomain.xml" -> + "text/x-cross-domain-policy"; + Name -> + case mochiweb_mime:from_extension(filename:extension(Name)) of + undefined -> + "text/plain"; + Mime -> + Mime + end + end. %% @spec parse_header(string()) -> {Type, [{K, V}]} %% @doc Parse a Content-Type like header, return the main Content-Type @@ -690,16 +690,16 @@ parse_header_test() -> parse_header("multipart/form-data;b=;cgi=\"i\\s;broken=true\"e;=z;z")), ok. -% guess_mime_test() -> -% ?assertEqual("text/plain", guess_mime("")), -% ?assertEqual("text/plain", guess_mime(".text")), -% ?assertEqual("application/zip", guess_mime(".zip")), -% ?assertEqual("application/zip", guess_mime("x.zip")), -% ?assertEqual("text/html", guess_mime("x.html")), -% ?assertEqual("application/xhtml+xml", guess_mime("x.xhtml")), -% ?assertEqual("text/x-cross-domain-policy", guess_mime("crossdomain.xml")), -% ?assertEqual("text/x-cross-domain-policy", guess_mime("www/crossdomain.xml")), -% ok. +guess_mime_test() -> + ?assertEqual("text/plain", guess_mime("")), + ?assertEqual("text/plain", guess_mime(".text")), + ?assertEqual("application/zip", guess_mime(".zip")), + ?assertEqual("application/zip", guess_mime("x.zip")), + ?assertEqual("text/html", guess_mime("x.html")), + ?assertEqual("application/xhtml+xml", guess_mime("x.xhtml")), + ?assertEqual("text/x-cross-domain-policy", guess_mime("crossdomain.xml")), + ?assertEqual("text/x-cross-domain-policy", guess_mime("www/crossdomain.xml")), + ok. path_split_test() -> {"", "foo/bar"} = path_split("/foo/bar"), diff --git a/deps/mochiweb/src/mochiweb_websocket.erl b/deps/mochiweb/src/mochiweb_websocket.erl new file mode 100644 index 0000000..ceb6bd6 --- /dev/null +++ b/deps/mochiweb/src/mochiweb_websocket.erl @@ -0,0 +1,281 @@ +-module(mochiweb_websocket). +-author('lukasz.lalik@zadane.pl'). + +%% The MIT License (MIT) + +%% Copyright (c) 2012 Zadane.pl sp. z o.o. + +%% 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. + +%% @doc Websockets module for Mochiweb. Based on Misultin websockets module. + +-export([loop/5, upgrade_connection/2, request/5]). +-export([send/3]). +-ifdef(TEST). +-compile(export_all). +-endif. + +loop(Socket, Body, State, WsVersion, ReplyChannel) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, 0}, {active, once}])), + proc_lib:hibernate(?MODULE, request, + [Socket, Body, State, WsVersion, ReplyChannel]). + +request(Socket, Body, State, WsVersion, ReplyChannel) -> + receive + {tcp_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {ssl_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {tcp_error, _, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {Proto, _, WsFrames} when Proto =:= tcp orelse Proto =:= ssl -> + case parse_frames(WsVersion, WsFrames, Socket) of + close -> + mochiweb_socket:close(Socket), + exit(normal); + error -> + mochiweb_socket:close(Socket), + exit(normal); + Payload -> + NewState = call_body(Body, Payload, State, ReplyChannel), + loop(Socket, Body, NewState, WsVersion, ReplyChannel) + end; + _ -> + mochiweb_socket:close(Socket), + exit(normal) + end. + +call_body({M, F, A}, Payload, State, ReplyChannel) -> + erlang:apply(M, F, [Payload, State, ReplyChannel | A]); +call_body({M, F}, Payload, State, ReplyChannel) -> + M:F(Payload, State, ReplyChannel); +call_body(Body, Payload, State, ReplyChannel) -> + Body(Payload, State, ReplyChannel). + +send(Socket, Payload, hybi) -> + Prefix = <<1:1, 0:3, 1:4, (payload_length(iolist_size(Payload)))/binary>>, + mochiweb_socket:send(Socket, [Prefix, Payload]); +send(Socket, Payload, hixie) -> + mochiweb_socket:send(Socket, [0, Payload, 255]). + +upgrade_connection(Req, Body) -> + case make_handshake(Req) of + {Version, Response} -> + Req:respond(Response), + Socket = Req:get(socket), + ReplyChannel = fun (Payload) -> + ?MODULE:send(Socket, Payload, Version) + end, + Reentry = fun (State) -> + ?MODULE:loop(Socket, Body, State, Version, ReplyChannel) + end, + {Reentry, ReplyChannel}; + _ -> + mochiweb_socket:close(Req:get(socket)), + exit(normal) + end. + +make_handshake(Req) -> + SecKey = Req:get_header_value("sec-websocket-key"), + Sec1Key = Req:get_header_value("Sec-WebSocket-Key1"), + Sec2Key = Req:get_header_value("Sec-WebSocket-Key2"), + Origin = Req:get_header_value(origin), + if SecKey =/= undefined -> + hybi_handshake(SecKey); + Sec1Key =/= undefined andalso Sec2Key =/= undefined -> + Host = Req:get_header_value("Host"), + Path = Req:get(path), + Body = Req:recv(8), + Scheme = scheme(Req), + hixie_handshake(Scheme, Host, Path, Sec1Key, Sec2Key, Body, Origin); + true -> + error + end. + +hybi_handshake(SecKey) -> + BinKey = list_to_binary(SecKey), + Bin = <>, + Challenge = base64:encode(crypto:hash(sha, Bin)), + Response = {101, [{"Connection", "Upgrade"}, + {"Upgrade", "websocket"}, + {"Sec-Websocket-Accept", Challenge}], ""}, + {hybi, Response}. + +scheme(Req) -> + case mochiweb_request:get(scheme, Req) of + http -> + "ws://"; + https -> + "wss://" + end. + +hixie_handshake(Scheme, Host, Path, Key1, Key2, Body, Origin) -> + Ikey1 = [D || D <- Key1, $0 =< D, D =< $9], + Ikey2 = [D || D <- Key2, $0 =< D, D =< $9], + Blank1 = length([D || D <- Key1, D =:= 32]), + Blank2 = length([D || D <- Key2, D =:= 32]), + Part1 = erlang:list_to_integer(Ikey1) div Blank1, + Part2 = erlang:list_to_integer(Ikey2) div Blank2, + Ckey = <>, + Challenge = erlang:md5(Ckey), + Location = lists:concat([Scheme, Host, Path]), + Response = {101, [{"Upgrade", "WebSocket"}, + {"Connection", "Upgrade"}, + {"Sec-WebSocket-Origin", Origin}, + {"Sec-WebSocket-Location", Location}], + Challenge}, + {hixie, Response}. + +parse_frames(hybi, Frames, Socket) -> + try parse_hybi_frames(Socket, Frames, []) of + Parsed -> process_frames(Parsed, []) + catch + _:_ -> error + end; +parse_frames(hixie, Frames, _Socket) -> + try parse_hixie_frames(Frames, []) of + Payload -> Payload + catch + _:_ -> error + end. + +%% +%% Websockets internal functions for RFC6455 and hybi draft +%% +process_frames([], Acc) -> + lists:reverse(Acc); +process_frames([{Opcode, Payload} | Rest], Acc) -> + case Opcode of + 8 -> close; + _ -> + process_frames(Rest, [Payload | Acc]) + end. + +parse_hybi_frames(_, <<>>, Acc) -> + lists:reverse(Acc); +parse_hybi_frames(S, <<_Fin:1, + _Rsv:3, + Opcode:4, + _Mask:1, + PayloadLen:7, + MaskKey:4/binary, + Payload:PayloadLen/binary-unit:8, + Rest/binary>>, + Acc) when PayloadLen < 126 -> + Payload2 = hybi_unmask(Payload, MaskKey, <<>>), + parse_hybi_frames(S, Rest, [{Opcode, Payload2} | Acc]); +parse_hybi_frames(S, <<_Fin:1, + _Rsv:3, + Opcode:4, + _Mask:1, + 126:7, + PayloadLen:16, + MaskKey:4/binary, + Payload:PayloadLen/binary-unit:8, + Rest/binary>>, + Acc) -> + Payload2 = hybi_unmask(Payload, MaskKey, <<>>), + parse_hybi_frames(S, Rest, [{Opcode, Payload2} | Acc]); +parse_hybi_frames(Socket, <<_Fin:1, + _Rsv:3, + _Opcode:4, + _Mask:1, + 126:7, + _PayloadLen:16, + _MaskKey:4/binary, + _/binary-unit:8>> = PartFrame, + Acc) -> + ok = mochiweb_socket:exit_if_closed(mochiweb_socket:setopts(Socket, [{packet, 0}, {active, once}])), + receive + {tcp_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {ssl_closed, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {tcp_error, _, _} -> + mochiweb_socket:close(Socket), + exit(normal); + {Proto, _, Continuation} when Proto =:= tcp orelse Proto =:= ssl -> + parse_hybi_frames(Socket, <>, + Acc); + _ -> + mochiweb_socket:close(Socket), + exit(normal) + after + 5000 -> + mochiweb_socket:close(Socket), + exit(normal) + end; +parse_hybi_frames(S, <<_Fin:1, + _Rsv:3, + Opcode:4, + _Mask:1, + 127:7, + 0:1, + PayloadLen:63, + MaskKey:4/binary, + Payload:PayloadLen/binary-unit:8, + Rest/binary>>, + Acc) -> + Payload2 = hybi_unmask(Payload, MaskKey, <<>>), + parse_hybi_frames(S, Rest, [{Opcode, Payload2} | Acc]). + +%% Unmasks RFC 6455 message +hybi_unmask(<>, MaskKey, Acc) -> + <> = MaskKey, + hybi_unmask(Rest, MaskKey, <>); +hybi_unmask(<>, MaskKey, Acc) -> + <> = MaskKey, + <>; +hybi_unmask(<>, MaskKey, Acc) -> + <> = MaskKey, + <>; +hybi_unmask(<>, MaskKey, Acc) -> + <> = MaskKey, + <>; +hybi_unmask(<<>>, _MaskKey, Acc) -> + Acc. + +payload_length(N) -> + case N of + N when N =< 125 -> << N >>; + N when N =< 16#ffff -> << 126, N:16 >>; + N when N =< 16#7fffffffffffffff -> << 127, N:64 >> + end. + + +%% +%% Websockets internal functions for hixie-76 websocket version +%% +parse_hixie_frames(<<>>, Frames) -> + lists:reverse(Frames); +parse_hixie_frames(<<0, T/binary>>, Frames) -> + {Frame, Rest} = parse_hixie(T, <<>>), + parse_hixie_frames(Rest, [Frame | Frames]). + +parse_hixie(<<255, Rest/binary>>, Buffer) -> + {Buffer, Rest}; +parse_hixie(<>, Buffer) -> + parse_hixie(T, <>). diff --git a/deps/mochiweb/src/reloader.erl b/deps/mochiweb/src/reloader.erl new file mode 100644 index 0000000..8130f45 --- /dev/null +++ b/deps/mochiweb/src/reloader.erl @@ -0,0 +1,179 @@ +%% @author Matthew Dempsky +%% @copyright 2007 Mochi Media, Inc. +%% +%% 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. + +%% @doc Erlang module for automatically reloading modified modules +%% during development. + +-module(reloader). +-author("Matthew Dempsky "). + +-include_lib("kernel/include/file.hrl"). + +-behaviour(gen_server). +-export([start/0, start_link/0]). +-export([stop/0]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). +-export([all_changed/0]). +-export([is_changed/1]). +-export([reload_modules/1]). +-record(state, {last, tref}). + +%% External API + +%% @spec start() -> ServerRet +%% @doc Start the reloader. +start() -> + gen_server:start({local, ?MODULE}, ?MODULE, [], []). + +%% @spec start_link() -> ServerRet +%% @doc Start the reloader. +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). + +%% @spec stop() -> ok +%% @doc Stop the reloader. +stop() -> + gen_server:call(?MODULE, stop). + +%% gen_server callbacks + +%% @spec init([]) -> {ok, State} +%% @doc gen_server init, opens the server in an initial state. +init([]) -> + {ok, TRef} = timer:send_interval(timer:seconds(1), doit), + {ok, #state{last = stamp(), tref = TRef}}. + +%% @spec handle_call(Args, From, State) -> tuple() +%% @doc gen_server callback. +handle_call(stop, _From, State) -> + {stop, shutdown, stopped, State}; +handle_call(_Req, _From, State) -> + {reply, {error, badrequest}, State}. + +%% @spec handle_cast(Cast, State) -> tuple() +%% @doc gen_server callback. +handle_cast(_Req, State) -> + {noreply, State}. + +%% @spec handle_info(Info, State) -> tuple() +%% @doc gen_server callback. +handle_info(doit, State) -> + Now = stamp(), + _ = doit(State#state.last, Now), + {noreply, State#state{last = Now}}; +handle_info(_Info, State) -> + {noreply, State}. + +%% @spec terminate(Reason, State) -> ok +%% @doc gen_server termination callback. +terminate(_Reason, State) -> + {ok, cancel} = timer:cancel(State#state.tref), + ok. + + +%% @spec code_change(_OldVsn, State, _Extra) -> State +%% @doc gen_server code_change callback (trivial). +code_change(_Vsn, State, _Extra) -> + {ok, State}. + +%% @spec reload_modules([atom()]) -> [{module, atom()} | {error, term()}] +%% @doc code:purge/1 and code:load_file/1 the given list of modules in order, +%% return the results of code:load_file/1. +reload_modules(Modules) -> + [begin code:purge(M), code:load_file(M) end || M <- Modules]. + +%% @spec all_changed() -> [atom()] +%% @doc Return a list of beam modules that have changed. +all_changed() -> + [M || {M, Fn} <- code:all_loaded(), is_list(Fn), is_changed(M)]. + +%% @spec is_changed(atom()) -> boolean() +%% @doc true if the loaded module is a beam with a vsn attribute +%% and does not match the on-disk beam file, returns false otherwise. +is_changed(M) -> + try + module_vsn(M:module_info()) =/= module_vsn(code:get_object_code(M)) + catch _:_ -> + false + end. + +%% Internal API + +module_vsn({M, Beam, _Fn}) -> + {ok, {M, Vsn}} = beam_lib:version(Beam), + Vsn; +module_vsn(L) when is_list(L) -> + {_, Attrs} = lists:keyfind(attributes, 1, L), + {_, Vsn} = lists:keyfind(vsn, 1, Attrs), + Vsn. + +doit(From, To) -> + [case file:read_file_info(Filename) of + {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To -> + reload(Module); + {ok, _} -> + unmodified; + {error, enoent} -> + %% The Erlang compiler deletes existing .beam files if + %% recompiling fails. Maybe it's worth spitting out a + %% warning here, but I'd want to limit it to just once. + gone; + {error, Reason} -> + io:format("Error reading ~s's file info: ~p~n", + [Filename, Reason]), + error + end || {Module, Filename} <- code:all_loaded(), is_list(Filename)]. + +reload(Module) -> + io:format("Reloading ~p ...", [Module]), + code:purge(Module), + case code:load_file(Module) of + {module, Module} -> + io:format(" ok.~n"), + case erlang:function_exported(Module, test, 0) of + true -> + io:format(" - Calling ~p:test() ...", [Module]), + case catch Module:test() of + ok -> + io:format(" ok.~n"), + reload; + Reason -> + io:format(" fail: ~p.~n", [Reason]), + reload_but_test_failed + end; + false -> + reload + end; + {error, Reason} -> + io:format(" fail: ~p.~n", [Reason]), + error + end. + + +stamp() -> + erlang:localtime(). + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). +-endif. diff --git a/deps/mochiweb/support/templates/mochiwebapp.template b/deps/mochiweb/support/templates/mochiwebapp.template new file mode 100644 index 0000000..c56314c --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp.template @@ -0,0 +1,24 @@ +%% -*- erlang -*- +{variables, [{appid, "mochiwebapp"}, + {author, "Mochi Media "}, + {year, "2010"}, + {version, "0.1"}, + {port, 8080}, + {dest, "{{appid}}"}]}. +{dir, "{{dest}}"}. +{template, "mochiwebapp_skel/src/mochiapp.app.src", "{{dest}}/src/{{appid}}.app.src"}. +{template, "mochiwebapp_skel/src/mochiapp.erl", "{{dest}}/src/{{appid}}.erl"}. +{template, "mochiwebapp_skel/src/mochiapp_app.erl", "{{dest}}/src/{{appid}}_app.erl"}. +{template, "mochiwebapp_skel/src/mochiapp_deps.erl", "{{dest}}/src/{{appid}}_deps.erl"}. +{template, "mochiwebapp_skel/src/mochiapp_sup.erl", "{{dest}}/src/{{appid}}_sup.erl"}. +{template, "mochiwebapp_skel/src/mochiapp_web.erl", "{{dest}}/src/{{appid}}_web.erl"}. +{template, "mochiwebapp_skel/start-dev.sh", "{{dest}}/start-dev.sh"}. +{template, "mochiwebapp_skel/bench.sh", "{{dest}}/bench.sh"}. +{template, "mochiwebapp_skel/priv/www/index.html", "{{dest}}/priv/www/index.html"}. +{file, "../../.gitignore", "{{dest}}/.gitignore"}. +{file, "../../Makefile", "{{dest}}/Makefile"}. +{file, "mochiwebapp_skel/rebar.config", "{{dest}}/rebar.config"}. +{file, "../../rebar", "{{dest}}/rebar"}. +{chmod, 8#755, "{{dest}}/rebar"}. +{chmod, 8#755, "{{dest}}/start-dev.sh"}. +{chmod, 8#755, "{{dest}}/bench.sh"}. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/bench.sh b/deps/mochiweb/support/templates/mochiwebapp_skel/bench.sh new file mode 100755 index 0000000..eb6e9c9 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/bench.sh @@ -0,0 +1,19 @@ +#!/bin/sh + +# workaround for rebar mustache template bug +DEFAULT_PORT={{port}} +HOST=${HOST:-127.0.0.1} +PORT=${PORT:-${DEFAULT_PORT}} + +BENCH_RUN="siege -q -c400 -r100 -b http://$HOST:$PORT/hello_world" + +sleep 120 + +echo "" +echo "" +for i in `seq 1 10`; +do + echo "Running test #$i:" + $BENCH_RUN + sleep 90 +done diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/priv/www/index.html b/deps/mochiweb/support/templates/mochiwebapp_skel/priv/www/index.html new file mode 100644 index 0000000..40ac0c8 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/priv/www/index.html @@ -0,0 +1,8 @@ + + +It Worked + + +{{appid}} running. + + diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/rebar.config b/deps/mochiweb/support/templates/mochiwebapp_skel/rebar.config new file mode 100644 index 0000000..da4939c --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/rebar.config @@ -0,0 +1,7 @@ +%% -*- erlang -*- +{erl_opts, [debug_info]}. +{deps, [ + {mochiweb, ".*", + {git, "git://github.com/mochi/mochiweb.git", {branch, "master"}}}]}. +{cover_enabled, true}. +{eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.app.src b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.app.src new file mode 100644 index 0000000..c0bb11f --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.app.src @@ -0,0 +1,9 @@ +%% -*- erlang -*- +{application, {{appid}}, + [{description, "{{appid}}"}, + {vsn, "{{version}}"}, + {modules, []}, + {registered, []}, + {mod, {'{{appid}}_app', []}}, + {env, []}, + {applications, [kernel, stdlib, crypto]}]}. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.erl b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.erl new file mode 100644 index 0000000..9770f2c --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp.erl @@ -0,0 +1,30 @@ +%% @author {{author}} +%% @copyright {{year}} {{author}} + +%% @doc {{appid}}. + +-module({{appid}}). +-author("{{author}}"). +-export([start/0, stop/0]). + +ensure_started(App) -> + case application:start(App) of + ok -> + ok; + {error, {already_started, App}} -> + ok + end. + + +%% @spec start() -> ok +%% @doc Start the {{appid}} server. +start() -> + {{appid}}_deps:ensure(), + ensure_started(crypto), + application:start({{appid}}). + + +%% @spec stop() -> ok +%% @doc Stop the {{appid}} server. +stop() -> + application:stop({{appid}}). diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_app.erl b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_app.erl new file mode 100644 index 0000000..6bbb255 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_app.erl @@ -0,0 +1,22 @@ +%% @author {{author}} +%% @copyright {{appid}} {{author}} + +%% @doc Callbacks for the {{appid}} application. + +-module({{appid}}_app). +-author("{{author}}"). + +-behaviour(application). +-export([start/2,stop/1]). + + +%% @spec start(_Type, _StartArgs) -> ServerRet +%% @doc application start callback for {{appid}}. +start(_Type, _StartArgs) -> + {{appid}}_deps:ensure(), + {{appid}}_sup:start_link(). + +%% @spec stop(_State) -> ServerRet +%% @doc application stop callback for {{appid}}. +stop(_State) -> + ok. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_deps.erl b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_deps.erl new file mode 100644 index 0000000..ad151bc --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_deps.erl @@ -0,0 +1,84 @@ +%% @author {{author}} +%% @copyright {{year}} {{author}} + +%% @doc Ensure that the relatively-installed dependencies are on the code +%% loading path, and locate resources relative +%% to this application's path. + +-module({{appid}}_deps). +-author("{{author}}"). + +-export([ensure/0, ensure/1]). +-export([get_base_dir/0, get_base_dir/1]). +-export([local_path/1, local_path/2]). +-export([deps_on_path/0, new_siblings/1]). + +%% @spec deps_on_path() -> [ProjNameAndVers] +%% @doc List of project dependencies on the path. +deps_on_path() -> + F = fun (X, Acc) -> + ProjDir = filename:dirname(X), + case {filename:basename(X), + filename:basename(filename:dirname(ProjDir))} of + {"ebin", "deps"} -> + [filename:basename(ProjDir) | Acc]; + _ -> + Acc + end + end, + ordsets:from_list(lists:foldl(F, [], code:get_path())). + +%% @spec new_siblings(Module) -> [Dir] +%% @doc Find new siblings paths relative to Module that aren't already on the +%% code path. +new_siblings(Module) -> + Existing = deps_on_path(), + SiblingEbin = filelib:wildcard(local_path(["deps", "*", "ebin"], Module)), + Siblings = [filename:dirname(X) || X <- SiblingEbin, + ordsets:is_element( + filename:basename(filename:dirname(X)), + Existing) =:= false], + lists:filter(fun filelib:is_dir/1, + lists:append([[filename:join([X, "ebin"]), + filename:join([X, "include"])] || + X <- Siblings])). + + +%% @spec ensure(Module) -> ok +%% @doc Ensure that all ebin and include paths for dependencies +%% of the application for Module are on the code path. +ensure(Module) -> + code:add_paths(new_siblings(Module)), + code:clash(), + ok. + +%% @spec ensure() -> ok +%% @doc Ensure that the ebin and include paths for dependencies of +%% this application are on the code path. Equivalent to +%% ensure(?Module). +ensure() -> + ensure(?MODULE). + +%% @spec get_base_dir(Module) -> string() +%% @doc Return the application directory for Module. It assumes Module is in +%% a standard OTP layout application in the ebin or src directory. +get_base_dir(Module) -> + {file, Here} = code:is_loaded(Module), + filename:dirname(filename:dirname(Here)). + +%% @spec get_base_dir() -> string() +%% @doc Return the application directory for this application. Equivalent to +%% get_base_dir(?MODULE). +get_base_dir() -> + get_base_dir(?MODULE). + +%% @spec local_path([string()], Module) -> string() +%% @doc Return an application-relative directory from Module's application. +local_path(Components, Module) -> + filename:join([get_base_dir(Module) | Components]). + +%% @spec local_path(Components) -> string() +%% @doc Return an application-relative directory for this application. +%% Equivalent to local_path(Components, ?MODULE). +local_path(Components) -> + local_path(Components, ?MODULE). diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_sup.erl b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_sup.erl new file mode 100644 index 0000000..39db395 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_sup.erl @@ -0,0 +1,56 @@ +%% @author {{author}} +%% @copyright {{year}} {{author}} + +%% @doc Supervisor for the {{appid}} application. + +-module({{appid}}_sup). +-author("{{author}}"). + +-behaviour(supervisor). + +%% External exports +-export([start_link/0, upgrade/0]). + +%% supervisor callbacks +-export([init/1]). + +%% @spec start_link() -> ServerRet +%% @doc API for starting the supervisor. +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% @spec upgrade() -> ok +%% @doc Add processes if necessary. +upgrade() -> + {ok, {_, Specs}} = init([]), + + Old = sets:from_list( + [Name || {Name, _, _, _} <- supervisor:which_children(?MODULE)]), + New = sets:from_list([Name || {Name, _, _, _, _, _} <- Specs]), + Kill = sets:subtract(Old, New), + + sets:fold(fun (Id, ok) -> + supervisor:terminate_child(?MODULE, Id), + supervisor:delete_child(?MODULE, Id), + ok + end, ok, Kill), + + [supervisor:start_child(?MODULE, Spec) || Spec <- Specs], + ok. + +%% @spec init([]) -> SupervisorTree +%% @doc supervisor callback. +init([]) -> + Web = web_specs({{appid}}_web, {{port}}), + Processes = [Web], + Strategy = {one_for_one, 10, 10}, + {ok, + {Strategy, lists:flatten(Processes)}}. + +web_specs(Mod, Port) -> + WebConfig = [{ip, {0,0,0,0}}, + {port, Port}, + {docroot, {{appid}}_deps:local_path(["priv", "www"])}], + {Mod, + {Mod, start, [WebConfig]}, + permanent, 5000, worker, dynamic}. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_web.erl b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_web.erl new file mode 100644 index 0000000..8429a88 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/src/mochiapp_web.erl @@ -0,0 +1,71 @@ +%% @author {{author}} +%% @copyright {{year}} {{author}} + +%% @doc Web server for {{appid}}. + +-module({{appid}}_web). +-author("{{author}}"). + +-export([start/1, stop/0, loop/2]). + +%% External API + +start(Options) -> + {DocRoot, Options1} = get_option(docroot, Options), + Loop = fun (Req) -> + ?MODULE:loop(Req, DocRoot) + end, + mochiweb_http:start([{name, ?MODULE}, {loop, Loop} | Options1]). + +stop() -> + mochiweb_http:stop(?MODULE). + +loop(Req, DocRoot) -> + "/" ++ Path = Req:get(path), + try + case Req:get(method) of + Method when Method =:= 'GET'; Method =:= 'HEAD' -> + case Path of + "hello_world" -> + Req:respond({200, [{"Content-Type", "text/plain"}], + "Hello world!\n"}); + _ -> + Req:serve_file(Path, DocRoot) + end; + 'POST' -> + case Path of + _ -> + Req:not_found() + end; + _ -> + Req:respond({501, [], []}) + end + catch + Type:What -> + Report = ["web request failed", + {path, Path}, + {type, Type}, {what, What}, + {trace, erlang:get_stacktrace()}], + error_logger:error_report(Report), + Req:respond({500, [{"Content-Type", "text/plain"}], + "request failed, sorry\n"}) + end. + +%% Internal API + +get_option(Option, Options) -> + {proplists:get_value(Option, Options), proplists:delete(Option, Options)}. + +%% +%% Tests +%% +-ifdef(TEST). +-include_lib("eunit/include/eunit.hrl"). + +you_should_write_a_test() -> + ?assertEqual( + "No, but I will!", + "Have you written any tests?"), + ok. + +-endif. diff --git a/deps/mochiweb/support/templates/mochiwebapp_skel/start-dev.sh b/deps/mochiweb/support/templates/mochiwebapp_skel/start-dev.sh new file mode 100755 index 0000000..65c1692 --- /dev/null +++ b/deps/mochiweb/support/templates/mochiwebapp_skel/start-dev.sh @@ -0,0 +1,7 @@ +#!/bin/sh +exec erl \ + -pa ebin deps/*/ebin \ + -boot start_sasl \ + -sname {{appid}}_dev \ + -s {{appid}} \ + -s reloader diff --git a/deps/mochiweb/support/test-materials/test_ssl_cert.pem b/deps/mochiweb/support/test-materials/test_ssl_cert.pem new file mode 100644 index 0000000..f84ccca --- /dev/null +++ b/deps/mochiweb/support/test-materials/test_ssl_cert.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIJAJLkNZzERPIUMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV +BAMTCWxvY2FsaG9zdDAeFw0xMDAzMTgxOTM5MThaFw0yMDAzMTUxOTM5MThaMBQx +EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAJeUCOZxbmtngF4S5lXckjSDLc+8C+XjMBYBPyy5eKdJY20AQ1s9/hhp3ulI +8pAvl+xVo4wQ+iBSvOzcy248Q+Xi6+zjceF7UNRgoYPgtJjKhdwcHV3mvFFrS/fp +9ggoAChaJQWDO1OCfUgTWXImhkw+vcDR11OVMAJ/h73dqzJPI9mfq44PTTHfYtgr +v4LAQAOlhXIAa2B+a6PlF6sqDqJaW5jLTcERjsBwnRhUGi7JevQzkejujX/vdA+N +jRBjKH/KLU5h3Q7wUchvIez0PXWVTCnZjpA9aR4m7YV05nKQfxtGd71czYDYk+j8 +hd005jetT4ir7JkAWValBybJVksCAwEAAaN1MHMwHQYDVR0OBBYEFJl9s51SnjJt +V/wgKWqV5Q6jnv1ZMEQGA1UdIwQ9MDuAFJl9s51SnjJtV/wgKWqV5Q6jnv1ZoRik +FjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCS5DWcxETyFDAMBgNVHRMEBTADAQH/ +MA0GCSqGSIb3DQEBBQUAA4IBAQB2ldLeLCc+lxK5i0EZquLamMBJwDIjGpT0JMP9 +b4XQOK2JABIu54BQIZhwcjk3FDJz/uOW5vm8k1kYni8FCjNZAaRZzCUfiUYTbTKL +Rq9LuIAODyP2dnTqyKaQOOJHvrx9MRZ3XVecXPS0Tib4aO57vCaAbIkmhtYpTWmw +e3t8CAIDVtgvjR6Se0a1JA4LktR7hBu22tDImvCSJn1nVAaHpani6iPBPPdMuMsP +TBoeQfj8VpqBUjCStqJGa8ytjDFX73YaxV2mgrtGwPNme1x3YNRR11yTu7tksyMO +GrmgxNriqYRchBhNEf72AKF0LR1ByKwfbDB9rIsV00HtCgOp +-----END CERTIFICATE----- diff --git a/deps/mochiweb/support/test-materials/test_ssl_key.pem b/deps/mochiweb/support/test-materials/test_ssl_key.pem new file mode 100644 index 0000000..69bbf82 --- /dev/null +++ b/deps/mochiweb/support/test-materials/test_ssl_key.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAl5QI5nFua2eAXhLmVdySNIMtz7wL5eMwFgE/LLl4p0ljbQBD +Wz3+GGne6UjykC+X7FWjjBD6IFK87NzLbjxD5eLr7ONx4XtQ1GChg+C0mMqF3Bwd +Xea8UWtL9+n2CCgAKFolBYM7U4J9SBNZciaGTD69wNHXU5UwAn+Hvd2rMk8j2Z+r +jg9NMd9i2Cu/gsBAA6WFcgBrYH5ro+UXqyoOolpbmMtNwRGOwHCdGFQaLsl69DOR +6O6Nf+90D42NEGMof8otTmHdDvBRyG8h7PQ9dZVMKdmOkD1pHibthXTmcpB/G0Z3 +vVzNgNiT6PyF3TTmN61PiKvsmQBZVqUHJslWSwIDAQABAoIBACI8Ky5xHDFh9RpK +Rn/KC7OUlTpADKflgizWJ0Cgu2F9L9mkn5HyFHvLHa+u7CootbWJOiEejH/UcBtH +WyMQtX0snYCpdkUpJv5wvMoebGu+AjHOn8tfm9T/2O6rhwgckLyMb6QpGbMo28b1 +p9QiY17BJPZx7qJQJcHKsAvwDwSThlb7MFmWf42LYWlzybpeYQvwpd+UY4I0WXLu +/dqJIS9Npq+5Y5vbo2kAEAssb2hSCvhCfHmwFdKmBzlvgOn4qxgZ1iHQgfKI6Z3Y +J0573ZgOVTuacn+lewtdg5AaHFcl/zIYEr9SNqRoPNGbPliuv6k6N2EYcufWL5lR +sCmmmHECgYEAxm+7OpepGr++K3+O1e1MUhD7vSPkKJrCzNtUxbOi2NWj3FFUSPRU +adWhuxvUnZgTcgM1+KuQ0fB2VmxXe9IDcrSFS7PKFGtd2kMs/5mBw4UgDZkOQh+q +kDiBEV3HYYJWRq0w3NQ/9Iy1jxxdENHtGmG9aqamHxNtuO608wGW2S8CgYEAw4yG +ZyAic0Q/U9V2OHI0MLxLCzuQz17C2wRT1+hBywNZuil5YeTuIt2I46jro6mJmWI2 +fH4S/geSZzg2RNOIZ28+aK79ab2jWBmMnvFCvaru+odAuser4N9pfAlHZvY0pT+S +1zYX3f44ygiio+oosabLC5nWI0zB2gG8pwaJlaUCgYEAgr7poRB+ZlaCCY0RYtjo +mYYBKD02vp5BzdKSB3V1zeLuBWM84pjB6b3Nw0fyDig+X7fH3uHEGN+USRs3hSj6 +BqD01s1OT6fyfbYXNw5A1r+nP+5h26Wbr0zblcKxdQj4qbbBZC8hOJNhqTqqA0Qe +MmzF7jiBaiZV/Cyj4x1f9BcCgYEAhjL6SeuTuOctTqs/5pz5lDikh6DpUGcH8qaV +o6aRAHHcMhYkZzpk8yh1uUdD7516APmVyvn6rrsjjhLVq4ZAJjwB6HWvE9JBN0TR +bILF+sREHUqU8Zn2Ku0nxyfXCKIOnxlx/J/y4TaGYqBqfXNFWiXNUrjQbIlQv/xR +K48g/MECgYBZdQlYbMSDmfPCC5cxkdjrkmAl0EgV051PWAi4wR+hLxIMRjHBvAk7 +IweobkFvT4TICulgroLkYcSa5eOZGxB/DHqcQCbWj3reFV0VpzmTDoFKG54sqBRl +vVntGt0pfA40fF17VoS7riAdHF53ippTtsovHEsg5tq5NrBl5uKm2g== +-----END RSA PRIVATE KEY----- diff --git a/rabbitmq-server/deps/rabbit/CODE_OF_CONDUCT.md b/deps/rabbit/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbit/CODE_OF_CONDUCT.md rename to deps/rabbit/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbit_common/CONTRIBUTING.md b/deps/rabbit/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbit_common/CONTRIBUTING.md rename to deps/rabbit/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbit/INSTALL b/deps/rabbit/INSTALL similarity index 100% rename from rabbitmq-server/deps/rabbit/INSTALL rename to deps/rabbit/INSTALL diff --git a/rabbitmq-server/deps/rabbit/LICENSE b/deps/rabbit/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbit/LICENSE rename to deps/rabbit/LICENSE diff --git a/deps/rabbit/LICENSE-MIT-Mochi b/deps/rabbit/LICENSE-MIT-Mochi new file mode 100644 index 0000000..c85b65a --- /dev/null +++ b/deps/rabbit/LICENSE-MIT-Mochi @@ -0,0 +1,9 @@ +This is the MIT license. + +Copyright (c) 2007 Mochi Media, Inc. + +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. diff --git a/rabbitmq-server/deps/rabbit/LICENSE-MPL-RabbitMQ b/deps/rabbit/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbit/LICENSE-MPL-RabbitMQ rename to deps/rabbit/LICENSE-MPL-RabbitMQ diff --git a/deps/rabbit/Makefile b/deps/rabbit/Makefile new file mode 100644 index 0000000..d1ffa56 --- /dev/null +++ b/deps/rabbit/Makefile @@ -0,0 +1,118 @@ +PROJECT = rabbit +VERSION ?= $(call get_app_version,src/$(PROJECT).app.src) + +DEPS = ranch rabbit_common +TEST_DEPS = rabbitmq_ct_helpers amqp_client meck proper + +define usage_xml_to_erl +$(subst __,_,$(patsubst $(DOCS_DIR)/rabbitmq%.1.xml, src/rabbit_%_usage.erl, $(subst -,_,$(1)))) +endef + +DOCS_DIR = docs +MANPAGES = $(patsubst %.xml, %, $(wildcard $(DOCS_DIR)/*.[0-9].xml)) +WEB_MANPAGES = $(patsubst %.xml, %.man.xml, $(wildcard $(DOCS_DIR)/*.[0-9].xml) $(DOCS_DIR)/rabbitmq-service.xml $(DOCS_DIR)/rabbitmq-echopid.xml) +USAGES_XML = $(DOCS_DIR)/rabbitmqctl.1.xml $(DOCS_DIR)/rabbitmq-plugins.1.xml +USAGES_ERL = $(foreach XML, $(USAGES_XML), $(call usage_xml_to_erl, $(XML))) + +EXTRA_SOURCES += $(USAGES_ERL) + +.DEFAULT_GOAL = all +$(PROJECT).d:: $(EXTRA_SOURCES) + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-build.mk \ + rabbit_common/mk/rabbitmq-run.mk \ + rabbit_common/mk/rabbitmq-dist.mk \ + rabbit_common/mk/rabbitmq-tools.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk + +# -------------------------------------------------------------------- +# Compilation. +# -------------------------------------------------------------------- + +RMQ_ERLC_OPTS += -I $(DEPS_DIR)/rabbit_common/include + +ifdef INSTRUMENT_FOR_QC +RMQ_ERLC_OPTS += -DINSTR_MOD=gm_qc +else +RMQ_ERLC_OPTS += -DINSTR_MOD=gm +endif + +ifdef CREDIT_FLOW_TRACING +RMQ_ERLC_OPTS += -DCREDIT_FLOW_TRACING=true +endif + +ifndef USE_PROPER_QC +# PropEr needs to be installed for property checking +# http://proper.softlab.ntua.gr/ +USE_PROPER_QC := $(shell $(ERL) -eval 'io:format({module, proper} =:= code:ensure_loaded(proper)), halt().') +RMQ_ERLC_OPTS += $(if $(filter true,$(USE_PROPER_QC)),-Duse_proper_qc) +endif + +clean:: clean-extra-sources + +clean-extra-sources: + $(gen_verbose) rm -f $(EXTRA_SOURCES) + +# -------------------------------------------------------------------- +# Documentation. +# -------------------------------------------------------------------- + +# xmlto can not read from standard input, so we mess with a tmp file. +%: %.xml $(DOCS_DIR)/examples-to-end.xsl + $(gen_verbose) xmlto --version | \ + grep -E '^xmlto version 0\.0\.([0-9]|1[1-8])$$' >/dev/null || \ + opt='--stringparam man.indent.verbatims=0' ; \ + xsltproc --novalid $(DOCS_DIR)/examples-to-end.xsl $< > $<.tmp && \ + xmlto -vv -o $(DOCS_DIR) $$opt man $< 2>&1 | (grep -v '^Note: Writing' || :) && \ + test -f $@ && \ + rm $<.tmp + +# Use tmp files rather than a pipeline so that we get meaningful errors +# Do not fold the cp into previous line, it's there to stop the file being +# generated but empty if we fail +define usage_dep +$(call usage_xml_to_erl, $(1)):: $(1) $(DOCS_DIR)/usage.xsl + $$(gen_verbose) xsltproc --novalid --stringparam modulename "`basename $$@ .erl`" \ + $(DOCS_DIR)/usage.xsl $$< > $$@.tmp && \ + sed -e 's/"/\\"/g' -e 's/%QUOTE%/"/g' $$@.tmp > $$@.tmp2 && \ + fold -s $$@.tmp2 > $$@.tmp3 && \ + mv $$@.tmp3 $$@ && \ + rm $$@.tmp $$@.tmp2 +endef + +$(foreach XML,$(USAGES_XML),$(eval $(call usage_dep, $(XML)))) + +# We rename the file before xmlto sees it since xmlto will use the name of +# the file to make internal links. +%.man.xml: %.xml $(DOCS_DIR)/html-to-website-xml.xsl + $(gen_verbose) cp $< `basename $< .xml`.xml && \ + xmlto xhtml-nochunks `basename $< .xml`.xml ; \ + rm `basename $< .xml`.xml && \ + cat `basename $< .xml`.html | \ + xsltproc --novalid $(DOCS_DIR)/remove-namespaces.xsl - | \ + xsltproc --novalid --stringparam original `basename $<` $(DOCS_DIR)/html-to-website-xml.xsl - | \ + xmllint --format - > $@ && \ + rm `basename $< .xml`.html + +.PHONY: manpages web-manpages distclean-manpages + +docs:: manpages web-manpages + +manpages: $(MANPAGES) + @: + +web-manpages: $(WEB_MANPAGES) + @: + +distclean:: distclean-manpages + +distclean-manpages:: + $(gen_verbose) rm -f $(MANPAGES) $(WEB_MANPAGES) diff --git a/deps/rabbit/README b/deps/rabbit/README new file mode 100644 index 0000000..43bfe00 --- /dev/null +++ b/deps/rabbit/README @@ -0,0 +1 @@ +See http://rabbitmq.com and https://github.com/rabbitmq/rabbitmq-server. diff --git a/rabbitmq-server/deps/rabbit/README.md b/deps/rabbit/README.md similarity index 97% rename from rabbitmq-server/deps/rabbit/README.md rename to deps/rabbit/README.md index 9930a66..ae8fd80 100644 --- a/rabbitmq-server/deps/rabbit/README.md +++ b/deps/rabbit/README.md @@ -46,4 +46,4 @@ RabbitMQ server is [licensed under the MPL](LICENSE-MPL-RabbitMQ). ## Copyright -(c) Pivotal Software Inc., 2007-2017. +(c) Pivotal Software Inc., 2007-2016. diff --git a/rabbitmq-server/deps/rabbit/check_xref b/deps/rabbit/check_xref similarity index 100% rename from rabbitmq-server/deps/rabbit/check_xref rename to deps/rabbit/check_xref diff --git a/rabbitmq-server/deps/rabbit/docs/README-for-packages b/deps/rabbit/docs/README-for-packages similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/README-for-packages rename to deps/rabbit/docs/README-for-packages diff --git a/rabbitmq-server/deps/rabbit/docs/examples-to-end.xsl b/deps/rabbit/docs/examples-to-end.xsl similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/examples-to-end.xsl rename to deps/rabbit/docs/examples-to-end.xsl diff --git a/rabbitmq-server/deps/rabbit/docs/html-to-website-xml.xsl b/deps/rabbit/docs/html-to-website-xml.xsl similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/html-to-website-xml.xsl rename to deps/rabbit/docs/html-to-website-xml.xsl diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-echopid.xml b/deps/rabbit/docs/rabbitmq-echopid.xml similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-echopid.xml rename to deps/rabbit/docs/rabbitmq-echopid.xml diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-env.conf.5.xml b/deps/rabbit/docs/rabbitmq-env.conf.5.xml similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-env.conf.5.xml rename to deps/rabbit/docs/rabbitmq-env.conf.5.xml diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-plugins.1.xml b/deps/rabbit/docs/rabbitmq-plugins.1.xml similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-plugins.1.xml rename to deps/rabbit/docs/rabbitmq-plugins.1.xml diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-server.1.xml b/deps/rabbit/docs/rabbitmq-server.1.xml similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-server.1.xml rename to deps/rabbit/docs/rabbitmq-server.1.xml diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-server.service.example b/deps/rabbit/docs/rabbitmq-server.service.example similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-server.service.example rename to deps/rabbit/docs/rabbitmq-server.service.example diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq-service.xml b/deps/rabbit/docs/rabbitmq-service.xml similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq-service.xml rename to deps/rabbit/docs/rabbitmq-service.xml diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmq.config.example b/deps/rabbit/docs/rabbitmq.config.example similarity index 94% rename from rabbitmq-server/deps/rabbit/docs/rabbitmq.config.example rename to deps/rabbit/docs/rabbitmq.config.example index 141e737..f425726 100644 --- a/rabbitmq-server/deps/rabbit/docs/rabbitmq.config.example +++ b/deps/rabbit/docs/rabbitmq.config.example @@ -236,18 +236,8 @@ %% Fraction of the high watermark limit at which queues start to %% page message out to disc in order to free up memory. - %% For example, when vm_memory_high_watermark is set to 0.4 and this value is set to 0.5, - %% paging can begin as early as when 20% of total available RAM is used by the node. %% - %% Values greater than 1.0 can be dangerous and should be used carefully. - %% - %% One alternative to this is to use durable queues and publish messages - %% as persistent (delivery mode = 2). With this combination queues will - %% move messages to disk much more rapidly. - %% - %% Another alternative is to configure queues to page all messages (both - %% persistent and transient) to disk as quickly - %% as possible, see http://www.rabbitmq.com/lazy-queues.html. + %% Values greater than 0.9 can be dangerous and should be used carefully. %% %% {vm_memory_high_watermark_paging_ratio, 0.5}, @@ -256,10 +246,6 @@ %% %% {memory_monitor_interval, 2500}, - %% The total memory available can be calculated from the OS resources - %% - default option - or provided as a configuration parameter: - %% {total_memory_available_override_value, "5000MB"}, - %% Set disk free limit (in bytes). Once free disk space reaches this %% lower bound, a disk alarm will be set - see the documentation %% listed above for more details. @@ -318,28 +304,15 @@ %% %% {hipe_compile, true}, - %% Number of times to retry while waiting for Mnesia tables in a cluster to + %% Timeout used when waiting for Mnesia tables in a cluster to %% become available. %% - %% {mnesia_table_loading_retry_limit, 10}, - - %% Time to wait per retry for Mnesia tables in a cluster to become - %% available. - %% - %% {mnesia_table_loading_retry_timeout, 30000}, + %% {mnesia_table_loading_timeout, 30000}, %% Size in bytes below which to embed messages in the queue index. See %% http://www.rabbitmq.com/persistence-conf.html %% - %% {queue_index_embed_msgs_below, 4096}, - - %% Whether or not to enable background GC. - %% - %% {background_gc_enabled, false}, - %% - %% Interval (in milliseconds) at which we run background GC. - %% - %% {background_gc_target_interval, 60000} + %% {queue_index_embed_msgs_below, 4096} ]}, diff --git a/rabbitmq-server/deps/rabbit/docs/rabbitmqctl.1.xml b/deps/rabbit/docs/rabbitmqctl.1.xml similarity index 92% rename from rabbitmq-server/deps/rabbit/docs/rabbitmqctl.1.xml rename to deps/rabbit/docs/rabbitmqctl.1.xml index 6f4c74c..217d2d9 100644 --- a/rabbitmq-server/deps/rabbit/docs/rabbitmqctl.1.xml +++ b/deps/rabbit/docs/rabbitmqctl.1.xml @@ -135,28 +135,6 @@ - - shutdown - - - Shuts down the Erlang process on which RabbitMQ is running. The - command is blocking and will return after the Erlang process - exits. If RabbitMQ fails to stop, it will return a non-zero exit - code. - - - Unlike the stop command, the shutdown command: - * does not require a pid_file to wait for the Erlang process to exit - * if RabbitMQ node is not running, it will return a non-zero exit code - - For example: - rabbitmqctl shutdown - - This command shuts down the Erlang process on which RabbitMQ is running. - - - - stop_app @@ -1057,16 +1035,11 @@ Certain features of RabbitMQ (such as the federation plugin) are controlled by dynamic, - cluster-wide parameters. - There are 2 kinds of parameters: parameters scoped to - a virtual host and global parameters. - Each vhost-scoped parameter - consists of a component name, a name and a value. - The component name and name are - strings, and the value is an Erlang term. - A global parameter consists of a name and value. The name - is a string and the value is an Erlang term. - Parameters can be set, cleared and listed. In general you should refer to the + cluster-wide parameters. Each parameter + consists of a component name, a name and a value, and is + associated with a virtual host. The component name and name are + strings, and the value is an Erlang term. Parameters can be + set, cleared and listed. In general you should refer to the documentation for the feature in question to see how to set parameters. @@ -1148,72 +1121,6 @@ - - set_global_parameter name value - - - Sets a global runtime parameter. This is similar to set_parameter - but the key-value pair isn't tied to a virtual host. - - - - name - - The name of the global runtime parameter being set. - - - - value - - The value for the global runtime parameter, as a - JSON term. In most shells you are very likely to - need to quote this. - - - - For example: - rabbitmqctl set_global_parameter mqtt_default_vhosts '{"O=client,CN=guest":"/"}' - - This command sets the global runtime parameter mqtt_default_vhosts to the JSON term {"O=client,CN=guest":"/"}. - - - - - clear_global_parameter name - - - Clears a global runtime parameter. This is similar to clear_global_parameter - but the key-value pair isn't tied to a virtual host. - - - - name - - The name of the global runtime parameter being cleared. - - - - For example: - rabbitmqctl clear_global_parameter mqtt_default_vhosts - - This command clears the global runtime parameter mqtt_default_vhosts. - - - - - list_global_parameters - - - Lists all global runtime parameters. This is similar to list_parameters - but the global runtime parameters are not tied to any virtual host. - - For example: - rabbitmqctl list_global_parameters - - This command lists all global parameters. - - - @@ -2167,9 +2074,9 @@ fraction - Limit relative to the total amount available RAM - as a non-negative floating point number. - Values lower than 1.0 can be dangerous and + Limit relative to the total amount available RAM + as a non-negative floating point number. + Values lower than 1.0 can be dangerous and should be used carefully. @@ -2189,7 +2096,7 @@ Flag to decrypt the input value. For example: - rabbitmqctl encode --decode '{encrypted, <<"...">>}' mypassphrase + rabbitmqctl encode --decode '{encrypted,'<<"...">>}' mypassphrase @@ -2205,7 +2112,7 @@ For example: rabbitmqctl encode '<<"guest">>' mypassphrase - rabbitmqctl encode --decode '{encrypted, <<"...">>}' mypassphrase + rabbitmqctl encode --decode '{encrypted,'<<"...">>}' mypassphrase @@ -2249,79 +2156,6 @@ rabbitmqctl encode --cipher blowfish_cfb64 --hash sha256 --iterations 10000 \ - - - - decode value passphrase--cipher cipher --hash hash --iterations iterations - - - - - - - value - passphrase - - - - - Value to decrypt (as produced by the encode command) and passphrase. - - For example: - rabbitmqctl decode '{encrypted, <<"...">>}' mypassphrase - - - - - - --cipher cipher - --hash hash - --iterations iterations - - - - - Options to specify the decryption settings. They can be used independently. - - For example: - -rabbitmqctl decode --cipher blowfish_cfb64 --hash sha256 --iterations 10000 \ -'{encrypted,<<"cU4kaour6KG8n/rC4IZT4MfKsS/th9gdAMWjcY9ygUPIwiW4BJmVyg==">>}' mypassphrase - - - - - - - - list_hashes - - - Lists hash functions supported by encoding commands. - - For example: - rabbitmqctl list_hashes - - This command instructs the RabbitMQ broker to list all - hash functions supported by encoding commands. - - - - - - list_ciphers - - - Lists cipher suites supported by encoding commands. - - For example: - rabbitmqctl list_ciphers - - This command instructs the RabbitMQ broker to list all - cipher suites supported by encoding commands. - - - diff --git a/rabbitmq-server/deps/rabbit/docs/remove-namespaces.xsl b/deps/rabbit/docs/remove-namespaces.xsl similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/remove-namespaces.xsl rename to deps/rabbit/docs/remove-namespaces.xsl diff --git a/rabbitmq-server/deps/rabbit/docs/set_rabbitmq_policy.sh.example b/deps/rabbit/docs/set_rabbitmq_policy.sh.example similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/set_rabbitmq_policy.sh.example rename to deps/rabbit/docs/set_rabbitmq_policy.sh.example diff --git a/rabbitmq-server/deps/rabbit/docs/usage.xsl b/deps/rabbit/docs/usage.xsl similarity index 100% rename from rabbitmq-server/deps/rabbit/docs/usage.xsl rename to deps/rabbit/docs/usage.xsl diff --git a/rabbitmq-server/deps/rabbit_common/erlang.mk b/deps/rabbit/erlang.mk similarity index 92% rename from rabbitmq-server/deps/rabbit_common/erlang.mk rename to deps/rabbit/erlang.mk index 89ba561..6d2a31c 100644 --- a/rabbitmq-server/deps/rabbit_common/erlang.mk +++ b/deps/rabbit/erlang.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -12,23 +12,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) -export ERLANG_MK_FILENAME - -ERLANG_MK_VERSION = 2.0.0-pre.2-256-g2cce185 -ERLANG_MK_WITHOUT = - -# Make 3.81 and 3.82 are deprecated. - -ifeq ($(MAKE_VERSION),3.81) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif -ifeq ($(MAKE_VERSION),3.82) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 # Core configuration. @@ -37,7 +25,6 @@ PROJECT := $(strip $(PROJECT)) PROJECT_VERSION ?= rolling PROJECT_MOD ?= $(PROJECT)_app -PROJECT_ENV ?= [] # Verbosity. @@ -98,8 +85,6 @@ all:: deps app rel rel:: $(verbose) : -relup:: deps app - check:: tests clean:: clean-crashdump @@ -117,7 +102,7 @@ distclean-tmp: help:: $(verbose) printf "%s\n" \ "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ - "Copyright (c) 2013-2016 Loïc Hoguin " \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ "" \ "Usage: [V=1] $(MAKE) [target]..." \ "" \ @@ -165,7 +150,30 @@ else core_native_path = $1 endif -core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$1) $2 +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) @@ -185,14 +193,13 @@ ERLANG_MK_COMMIT ?= ERLANG_MK_BUILD_CONFIG ?= build.config ERLANG_MK_BUILD_DIR ?= .erlang.mk.build -erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) ifdef ERLANG_MK_COMMIT cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) endif if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - $(MAKE) -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk rm -rf $(ERLANG_MK_BUILD_DIR) @@ -279,14 +286,6 @@ pkg_apns_fetch = git pkg_apns_repo = https://github.com/inaka/apns4erl pkg_apns_commit = master -PACKAGES += asciideck -pkg_asciideck_name = asciideck -pkg_asciideck_description = Asciidoc for Erlang. -pkg_asciideck_homepage = https://ninenines.eu -pkg_asciideck_fetch = git -pkg_asciideck_repo = https://github.com/ninenines/asciideck -pkg_asciideck_commit = master - PACKAGES += azdht pkg_azdht_name = azdht pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang @@ -407,14 +406,6 @@ pkg_bootstrap_fetch = git pkg_bootstrap_repo = https://github.com/schlagert/bootstrap pkg_bootstrap_commit = master -PACKAGES += boss -pkg_boss_name = boss -pkg_boss_description = Erlang web MVC, now featuring Comet -pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_fetch = git -pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_commit = master - PACKAGES += boss_db pkg_boss_db_name = boss_db pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang @@ -423,6 +414,14 @@ pkg_boss_db_fetch = git pkg_boss_db_repo = https://github.com/ErlyORM/boss_db pkg_boss_db_commit = master +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + PACKAGES += brod pkg_brod_name = brod pkg_brod_description = Kafka client in Erlang @@ -567,13 +566,13 @@ pkg_cloudi_service_api_requests_fetch = git pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests pkg_cloudi_service_api_requests_commit = master -PACKAGES += cloudi_service_db -pkg_cloudi_service_db_name = cloudi_service_db -pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) -pkg_cloudi_service_db_homepage = http://cloudi.org/ -pkg_cloudi_service_db_fetch = git -pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db -pkg_cloudi_service_db_commit = master +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master PACKAGES += cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra @@ -583,14 +582,6 @@ pkg_cloudi_service_db_cassandra_fetch = git pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_commit = master -PACKAGES += cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service -pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ -pkg_cloudi_service_db_cassandra_cql_fetch = git -pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_commit = master - PACKAGES += cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service @@ -647,6 +638,14 @@ pkg_cloudi_service_db_tokyotyrant_fetch = git pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_commit = master +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + PACKAGES += cloudi_service_filesystem pkg_cloudi_service_filesystem_name = cloudi_service_filesystem pkg_cloudi_service_filesystem_description = Filesystem CloudI Service @@ -1039,14 +1038,6 @@ pkg_edown_fetch = git pkg_edown_repo = https://github.com/uwiger/edown pkg_edown_commit = master -PACKAGES += eep -pkg_eep_name = eep -pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy -pkg_eep_homepage = https://github.com/virtan/eep -pkg_eep_fetch = git -pkg_eep_repo = https://github.com/virtan/eep -pkg_eep_commit = master - PACKAGES += eep_app pkg_eep_app_name = eep_app pkg_eep_app_description = Embedded Event Processing @@ -1055,6 +1046,14 @@ pkg_eep_app_fetch = git pkg_eep_app_repo = https://github.com/darach/eep-erl pkg_eep_app_commit = master +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + PACKAGES += efene pkg_efene_name = efene pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX @@ -1239,14 +1238,6 @@ pkg_eqm_fetch = git pkg_eqm_repo = https://github.com/loucash/eqm pkg_eqm_commit = master -PACKAGES += eredis -pkg_eredis_name = eredis -pkg_eredis_description = Erlang Redis client -pkg_eredis_homepage = https://github.com/wooga/eredis -pkg_eredis_fetch = git -pkg_eredis_repo = https://github.com/wooga/eredis -pkg_eredis_commit = master - PACKAGES += eredis_pool pkg_eredis_pool_name = eredis_pool pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. @@ -1255,6 +1246,14 @@ pkg_eredis_pool_fetch = git pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_commit = master +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + PACKAGES += erl_streams pkg_erl_streams_name = erl_streams pkg_erl_streams_description = Streams in Erlang @@ -1543,14 +1542,6 @@ pkg_etap_fetch = git pkg_etap_repo = https://github.com/ngerakines/etap pkg_etap_commit = master -PACKAGES += etest -pkg_etest_name = etest -pkg_etest_description = A lightweight, convention over configuration test framework for Erlang -pkg_etest_homepage = https://github.com/wooga/etest -pkg_etest_fetch = git -pkg_etest_repo = https://github.com/wooga/etest -pkg_etest_commit = master - PACKAGES += etest_http pkg_etest_http_name = etest_http pkg_etest_http_description = etest Assertions around HTTP (client-side) @@ -1559,6 +1550,14 @@ pkg_etest_http_fetch = git pkg_etest_http_repo = https://github.com/wooga/etest_http pkg_etest_http_commit = master +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + PACKAGES += etoml pkg_etoml_name = etoml pkg_etoml_description = TOML language erlang parser @@ -1567,14 +1566,6 @@ pkg_etoml_fetch = git pkg_etoml_repo = https://github.com/kalta/etoml pkg_etoml_commit = master -PACKAGES += eunit -pkg_eunit_name = eunit -pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. -pkg_eunit_homepage = https://github.com/richcarl/eunit -pkg_eunit_fetch = git -pkg_eunit_repo = https://github.com/richcarl/eunit -pkg_eunit_commit = master - PACKAGES += eunit_formatters pkg_eunit_formatters_name = eunit_formatters pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. @@ -1583,6 +1574,14 @@ pkg_eunit_formatters_fetch = git pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_commit = master +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + PACKAGES += euthanasia pkg_euthanasia_name = euthanasia pkg_euthanasia_description = Merciful killer for your Erlang processes @@ -1600,7 +1599,7 @@ pkg_evum_repo = https://github.com/msantos/evum pkg_evum_commit = master PACKAGES += exec -pkg_exec_name = erlexec +pkg_exec_name = exec pkg_exec_description = Execute and control OS processes from Erlang/OTP. pkg_exec_homepage = http://saleyn.github.com/erlexec pkg_exec_fetch = git @@ -1719,14 +1718,6 @@ pkg_fn_fetch = git pkg_fn_repo = https://github.com/reiddraper/fn pkg_fn_commit = master -PACKAGES += folsom -pkg_folsom_name = folsom -pkg_folsom_description = Expose Erlang Events and Metrics -pkg_folsom_homepage = https://github.com/boundary/folsom -pkg_folsom_fetch = git -pkg_folsom_repo = https://github.com/boundary/folsom -pkg_folsom_commit = master - PACKAGES += folsom_cowboy pkg_folsom_cowboy_name = folsom_cowboy pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. @@ -1735,6 +1726,14 @@ pkg_folsom_cowboy_fetch = git pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_commit = master +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + PACKAGES += folsomite pkg_folsomite_name = folsomite pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics @@ -2095,14 +2094,6 @@ pkg_jesse_fetch = git pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master -PACKAGES += jiffy -pkg_jiffy_name = jiffy -pkg_jiffy_description = JSON NIFs for Erlang. -pkg_jiffy_homepage = https://github.com/davisp/jiffy -pkg_jiffy_fetch = git -pkg_jiffy_repo = https://github.com/davisp/jiffy -pkg_jiffy_commit = master - PACKAGES += jiffy_v pkg_jiffy_v_name = jiffy_v pkg_jiffy_v_description = JSON validation utility @@ -2111,6 +2102,14 @@ pkg_jiffy_v_fetch = git pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v pkg_jiffy_v_commit = master +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + PACKAGES += jobs pkg_jobs_name = jobs pkg_jobs_description = a Job scheduler for load regulation @@ -2127,14 +2126,6 @@ pkg_joxa_fetch = git pkg_joxa_repo = https://github.com/joxa/joxa pkg_joxa_commit = master -PACKAGES += json -pkg_json_name = json -pkg_json_description = a high level json library for erlang (17.0+) -pkg_json_homepage = https://github.com/talentdeficit/json -pkg_json_fetch = git -pkg_json_repo = https://github.com/talentdeficit/json -pkg_json_commit = master - PACKAGES += json_rec pkg_json_rec_name = json_rec pkg_json_rec_description = JSON to erlang record @@ -2143,6 +2134,14 @@ pkg_json_rec_fetch = git pkg_json_rec_repo = https://github.com/justinkirby/json_rec pkg_json_rec_commit = master +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + PACKAGES += jsone pkg_jsone_name = jsone pkg_jsone_description = An Erlang library for encoding, decoding JSON data. @@ -2183,14 +2182,6 @@ pkg_jsx_fetch = git pkg_jsx_repo = https://github.com/talentdeficit/jsx pkg_jsx_commit = master -PACKAGES += kafka -pkg_kafka_name = kafka -pkg_kafka_description = Kafka consumer and producer in Erlang -pkg_kafka_homepage = https://github.com/wooga/kafka-erlang -pkg_kafka_fetch = git -pkg_kafka_repo = https://github.com/wooga/kafka-erlang -pkg_kafka_commit = master - PACKAGES += kafka_protocol pkg_kafka_protocol_name = kafka_protocol pkg_kafka_protocol_description = Kafka protocol Erlang library @@ -2199,6 +2190,14 @@ pkg_kafka_protocol_fetch = git pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git pkg_kafka_protocol_commit = master +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + PACKAGES += kai pkg_kai_name = kai pkg_kai_description = DHT storage by Takeshi Inoue @@ -2295,14 +2294,6 @@ pkg_kvs_fetch = git pkg_kvs_repo = https://github.com/synrc/kvs pkg_kvs_commit = master -PACKAGES += lager -pkg_lager_name = lager -pkg_lager_description = A logging framework for Erlang/OTP. -pkg_lager_homepage = https://github.com/basho/lager -pkg_lager_fetch = git -pkg_lager_repo = https://github.com/basho/lager -pkg_lager_commit = master - PACKAGES += lager_amqp_backend pkg_lager_amqp_backend_name = lager_amqp_backend pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend @@ -2319,6 +2310,14 @@ pkg_lager_syslog_fetch = git pkg_lager_syslog_repo = https://github.com/basho/lager_syslog pkg_lager_syslog_commit = master +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + PACKAGES += lambdapad pkg_lambdapad_name = lambdapad pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. @@ -2575,14 +2574,6 @@ pkg_mixer_fetch = git pkg_mixer_repo = https://github.com/chef/mixer pkg_mixer_commit = master -PACKAGES += mochiweb -pkg_mochiweb_name = mochiweb -pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. -pkg_mochiweb_homepage = https://github.com/mochi/mochiweb -pkg_mochiweb_fetch = git -pkg_mochiweb_repo = https://github.com/mochi/mochiweb -pkg_mochiweb_commit = master - PACKAGES += mochiweb_xpath pkg_mochiweb_xpath_name = mochiweb_xpath pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser @@ -2591,6 +2582,14 @@ pkg_mochiweb_xpath_fetch = git pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_commit = master +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + PACKAGES += mockgyver pkg_mockgyver_name = mockgyver pkg_mockgyver_description = A mocking library for Erlang @@ -3063,14 +3062,6 @@ pkg_quickrand_fetch = git pkg_quickrand_repo = https://github.com/okeuday/quickrand pkg_quickrand_commit = master -PACKAGES += rabbit -pkg_rabbit_name = rabbit -pkg_rabbit_description = RabbitMQ Server -pkg_rabbit_homepage = https://www.rabbitmq.com/ -pkg_rabbit_fetch = git -pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git -pkg_rabbit_commit = master - PACKAGES += rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak @@ -3079,6 +3070,14 @@ pkg_rabbit_exchange_type_riak_fetch = git pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_commit = master +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + PACKAGES += rack pkg_rack_name = rack pkg_rack_description = Rack handler for erlang @@ -3495,14 +3494,6 @@ pkg_smother_fetch = git pkg_smother_repo = https://github.com/ramsay-t/Smother pkg_smother_commit = master -PACKAGES += snappyer -pkg_snappyer_name = snappyer -pkg_snappyer_description = Snappy as nif for Erlang -pkg_snappyer_homepage = https://github.com/zmstone/snappyer -pkg_snappyer_fetch = git -pkg_snappyer_repo = https://github.com/zmstone/snappyer.git -pkg_snappyer_commit = master - PACKAGES += social pkg_social_name = social pkg_social_description = Cowboy handler for social login via OAuth2 providers @@ -3551,14 +3542,6 @@ pkg_stable_fetch = git pkg_stable_repo = https://github.com/dvv/stable pkg_stable_commit = master -PACKAGES += statebox -pkg_statebox_name = statebox -pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. -pkg_statebox_homepage = https://github.com/mochi/statebox -pkg_statebox_fetch = git -pkg_statebox_repo = https://github.com/mochi/statebox -pkg_statebox_commit = master - PACKAGES += statebox_riak pkg_statebox_riak_name = statebox_riak pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. @@ -3567,6 +3550,14 @@ pkg_statebox_riak_fetch = git pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak pkg_statebox_riak_commit = master +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + PACKAGES += statman pkg_statman_name = statman pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM @@ -3735,14 +3726,6 @@ pkg_tirerl_fetch = git pkg_tirerl_repo = https://github.com/inaka/tirerl pkg_tirerl_commit = master -PACKAGES += toml -pkg_toml_name = toml -pkg_toml_description = TOML (0.4.0) config parser -pkg_toml_homepage = http://dozzie.jarowit.net/trac/wiki/TOML -pkg_toml_fetch = git -pkg_toml_repo = https://github.com/dozzie/toml -pkg_toml_commit = v0.2.0 - PACKAGES += traffic_tools pkg_traffic_tools_name = traffic_tools pkg_traffic_tools_description = Simple traffic limiting library @@ -4079,7 +4062,7 @@ pkg_zucchini_fetch = git pkg_zucchini_repo = https://github.com/devinus/zucchini pkg_zucchini_commit = master -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: search @@ -4106,10 +4089,10 @@ else $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-deps clean-tmp-deps.log +.PHONY: distclean-deps # Configuration. @@ -4129,32 +4112,11 @@ export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR -# External "early" plugins (see core/plugins.mk for regular plugins). -# They both use the core_dep_plugin macro. - -define core_dep_plugin -ifeq ($(2),$(PROJECT)) --include $$(patsubst $(PROJECT)/%,%,$(1)) -else --include $(DEPS_DIR)/$(1) - -$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; -endif -endef - -DEP_EARLY_PLUGINS ?= - -$(foreach p,$(DEP_EARLY_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/early-plugins.mk,$p)))) - dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) -LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$(a)),$(APPS_DIR)/$(a))) ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) @@ -4177,7 +4139,10 @@ dep_verbose = $(dep_verbose_$(V)) # Core targets. -apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log endif @@ -4185,42 +4150,36 @@ endif # Create ebin directory for all apps to make sure Erlang recognizes them # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. -ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - mkdir -p $$dep/ebin; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ done -endif -# at the toplevel: if LOCAL_DEPS is defined with at least one local app, only -# compile that list of apps. otherwise, compile everything. -# within an app: compile all LOCAL_DEPS that are (uncompiled) local apps - $(verbose) set -e; for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ - $(MAKE) -C $$dep IS_APP=1; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ fi \ done - -clean-tmp-deps.log: -ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log endif ifneq ($(SKIP_DEPS),) deps:: else -deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) set -e; for dep in $(ALL_DEPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ - $(MAKE) -C $$dep IS_DEP=1; \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ else \ - echo "Error: No Makefile to build dependency $$dep." >&2; \ + echo "Error: No Makefile to build dependency $$dep."; \ exit 2; \ fi \ fi \ @@ -4234,18 +4193,17 @@ endif # in practice only Makefile is needed so far. define dep_autopatch if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ - rm -rf $(DEPS_DIR)/$1/ebin/; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ $(call dep_autopatch_erlang_mk,$(1)); \ elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ - if [ -f $(DEPS_DIR)/$1/rebar.lock ]; then \ - $(call dep_autopatch2,$1); \ - elif [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ @@ -4257,14 +4215,11 @@ define dep_autopatch endef define dep_autopatch2 - ! test -f $(DEPS_DIR)/$1/ebin/$1.app || \ - mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ - rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ fi; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ - if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script -o -f $(DEPS_DIR)/$1/rebar.lock ]; then \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ $(call dep_autopatch_fetch_rebar); \ $(call dep_autopatch_rebar,$(1)); \ else \ @@ -4276,15 +4231,11 @@ define dep_autopatch_noop printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile endef -# Replace "include erlang.mk" with a line that will load the parent Erlang.mk -# if given. Do it for all 3 possible Makefile file names. +# Overwrite erlang.mk with the current file by default. ifeq ($(NO_AUTOPATCH_ERLANG_MK),) define dep_autopatch_erlang_mk - $t for f in Makefile makefile GNUmakefile; do \ - if [ -f $(DEPS_DIR)/$1/$$f ]; then \ - sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \ - fi \ - done + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk endef else define dep_autopatch_erlang_mk @@ -4303,7 +4254,7 @@ define dep_autopatch_fetch_rebar if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ - git checkout -q 576e12171ab8d69b048b827b92aa65d067deea01; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ $(MAKE); \ cd -; \ fi @@ -4320,7 +4271,6 @@ endef define dep_autopatch_rebar.erl application:load(rebar), application:set_env(rebar, log_level, debug), - rmemo:start(), Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of {ok, Conf0} -> Conf0; _ -> [] @@ -4474,9 +4424,9 @@ define dep_autopatch_rebar.erl [] -> ok; _ -> Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), - PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -4515,7 +4465,7 @@ define dep_autopatch_rebar.erl "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", - [[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], Output, ": $$\(foreach ext,.c .C .cc .cpp,", "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", @@ -4527,7 +4477,7 @@ define dep_autopatch_rebar.erl end, [PortSpec(S) || S <- PortSpecs] end, - Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of false -> ok; @@ -4575,6 +4525,22 @@ define dep_autopatch_rebar.erl halt() endef +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", @@ -4622,16 +4588,21 @@ define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef -define dep_fetch_ln - ln -s $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() endef # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex - mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ - $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ - https://s3.amazonaws.com/s3.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ - tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); endef define dep_fetch_fail @@ -4661,7 +4632,7 @@ $(DEPS_DIR)/$(call dep_name,$1): $(eval DEP_NAME := $(call dep_name,$1)) $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ - echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) @@ -4703,15 +4674,15 @@ ifndef IS_APP clean:: clean-apps clean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep clean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ done distclean:: distclean-apps distclean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep distclean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ done endif @@ -4731,7 +4702,85 @@ ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log -# Copyright (c) 2015-2016, Loïc Hoguin +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Verbosity. @@ -4750,9 +4799,10 @@ endef define compile_proto.erl [begin + Dir = filename:dirname(filename:dirname(F)), protobuffs_compile:generate_source(F, - [{output_include_dir, "./include"}, - {output_src_dir, "./ebin"}]) + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) end || F <- string:tokens("$(1)", " ")], halt(). endef @@ -4762,7 +4812,7 @@ ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) $(if $(strip $?),$(call compile_proto,$?)) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app @@ -4776,8 +4826,6 @@ COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) ERLC_EXCLUDE ?= ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) -ERLC_ASN1_OPTS ?= - ERLC_MIB_OPTS ?= COMPILE_MIB_FIRST ?= COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) @@ -4827,27 +4875,25 @@ endif ifeq ($(wildcard src/$(PROJECT_MOD).erl),) define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} ]}. endef else define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {mod, {$(PROJECT_MOD), []}}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {mod, {$(PROJECT_MOD), []}} ]}. endef endif @@ -4857,10 +4903,8 @@ app-build: ebin/$(PROJECT).app # Source files. -ALL_SRC_FILES := $(sort $(call core_find,src/,*)) - -ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES)) -CORE_FILES := $(filter %.core,$(ALL_SRC_FILES)) +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) # ASN.1 files. @@ -4870,7 +4914,7 @@ ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) define compile_asn1 $(verbose) mkdir -p include/ - $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $(1) + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) $(verbose) mv asn1/*.erl src/ $(verbose) mv asn1/*.hrl include/ $(verbose) mv asn1/*.asn1db include/ @@ -4893,16 +4937,16 @@ endif # Leex and Yecc files. -XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES)) +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) ERL_FILES += $(XRL_ERL_FILES) -YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES)) +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) ERL_FILES += $(YRL_ERL_FILES) $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) - $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) # Erlang and Core Erlang files. @@ -4952,12 +4996,7 @@ define makedep.erl (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, import, {Imp, _}) -> - IsFile = - case lists:keyfind(Imp, 1, Modules) of - false -> false; - {_, FilePath} -> filelib:is_file(FilePath) - end, - case IsFile of + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of false -> ok; true -> Add(Mod, Imp) end; @@ -4981,17 +5020,9 @@ define makedep.erl end || F <- ErlFiles], Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], - TargetPath = fun(Target) -> - case lists:keyfind(Target, 1, Modules) of - false -> ""; - {_, DepFile} -> - DirSubname = tl(string:tokens(filename:dirname(DepFile), "/")), - string:join(DirSubname ++ [atom_to_list(Target)], "/") - end - end, ok = file:write_file("$(1)", [ [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], - "\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n" + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" ]), halt() endef @@ -5004,18 +5035,18 @@ endif ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) if test -f $@; then \ + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ fi - $(verbose) touch $@ + @touch $@ $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change endif -include $(wildcard $(PROJECT).d) +-include $(PROJECT).d ebin/$(PROJECT).app:: ebin/ @@ -5034,7 +5065,7 @@ ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.s $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) - $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ > ebin/$(PROJECT).app else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ @@ -5058,7 +5089,6 @@ clean-app: endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5076,10 +5106,10 @@ ifneq ($(SKIP_DEPS),) doc-deps: else doc-deps: $(ALL_DOC_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rel-deps @@ -5096,10 +5126,10 @@ ifneq ($(SKIP_DEPS),) rel-deps: else rel-deps: $(ALL_REL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: test-deps test-dir test-build clean-test-dir @@ -5121,7 +5151,7 @@ ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done endif ifneq ($(wildcard $(TEST_DIR)),) @@ -5154,7 +5184,7 @@ ifneq ($(wildcard $(TEST_DIR)/*.beam),) endif endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rebar.config @@ -5190,90 +5220,54 @@ $(eval export _compat_rebar_config) rebar.config: $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck) +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc -.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual - -# Core targets. +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 docs:: asciidoc -distclean:: distclean-asciidoc-guide distclean-asciidoc-manual - -# Plugin-specific targets. - asciidoc: asciidoc-guide asciidoc-manual -# User guide. - ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else -asciidoc-guide: distclean-asciidoc-guide doc-deps +asciidoc-guide: distclean-asciidoc doc-deps a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ - -distclean-asciidoc-guide: - $(gen_verbose) rm -rf doc/html/ doc/guide.pdf endif -# Man pages. - -ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc) - -ifeq ($(ASCIIDOC_MANUAL_FILES),) +ifeq ($(wildcard doc/src/manual/*.asciidoc),) asciidoc-manual: else - -# Configuration. - -MAN_INSTALL_PATH ?= /usr/local/share/man -MAN_SECTIONS ?= 3 7 -MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/') -MAN_VERSION ?= $(PROJECT_VERSION) - -# Plugin-specific targets. - -define asciidoc2man.erl -try - [begin - io:format(" ADOC ~s~n", [F]), - ok = asciideck:to_manpage(asciideck:parse_file(F), #{ - compress => gzip, - outdir => filename:dirname(F), - extra2 => "$(MAN_PROJECT) $(MAN_VERSION)", - extra3 => "$(MAN_PROJECT) Function Reference" - }) - end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]], - halt(0) -catch C:E -> - io:format("Exception ~p:~p~nStacktrace: ~p~n", [C, E, erlang:get_stacktrace()]), - halt(1) -end. -endef - -asciidoc-manual:: doc-deps - -asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) - $(call erlang,$(call asciidoc2man.erl,$?)) - $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done install-docs:: install-asciidoc install-asciidoc: asciidoc-manual - $(foreach s,$(MAN_SECTIONS),\ - mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ - install -g `id -u` -o `id -g` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) - -distclean-asciidoc-manual: - $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) -endif + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done endif -# Copyright (c) 2014-2016, Loïc Hoguin +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates @@ -5330,7 +5324,7 @@ ifdef SP define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 # Whitespace to be used when creating files from templates. SP = $(SP) @@ -5340,7 +5334,7 @@ else define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 endef endif @@ -5348,7 +5342,7 @@ endif define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk endef @@ -5368,7 +5362,7 @@ stop(_State) -> endef define bs_relx_config -{release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. +{release, {$p_release, "1"}, [$p]}. {extended_start_script, true}. {sys_config, "rel/sys.config"}. {vm_args, "rel/vm.args"}. @@ -5719,6 +5713,9 @@ endif ifndef t $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif +ifndef tpl_$(t) + $(error Unknown template) +endif ifndef n $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif @@ -5731,7 +5728,7 @@ endif list-templates: $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) -# Copyright (c) 2014-2016, Loïc Hoguin +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-c_src distclean-c_src-env @@ -5966,94 +5963,56 @@ else $(call render_template,bs_erl_nif,src/$n.erl) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ci ci-prepare ci-setup distclean-kerl - -CI_OTP ?= -CI_HIPE ?= -CI_ERLLVM ?= - -ifeq ($(CI_VM),native) -ERLC_OPTS += +native -TEST_ERLC_OPTS += +native -else ifeq ($(CI_VM),erllvm) -ERLC_OPTS += +native +'{hipe, [to_llvm]}' -TEST_ERLC_OPTS += +native +'{hipe, [to_llvm]}' -endif - -ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) -ci:: -else - -ifeq ($(strip $(KERL)),) -KERL := $(ERLANG_MK_TMP)/kerl/kerl -endif +.PHONY: ci ci-setup distclean-kerl +KERL ?= $(CURDIR)/kerl export KERL -KERL_GIT ?= https://github.com/kerl/kerl -KERL_COMMIT ?= master - -KERL_MAKEFLAGS ?= +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl OTP_GIT ?= https://github.com/erlang/otp CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= -ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) -ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) ci-setup:: -ci-extra:: - ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target -ci-$1: $(CI_INSTALL_DIR)/$2 - $(verbose) $(MAKE) --no-print-directory clean +ci-$(1): $(CI_INSTALL_DIR)/$(1) $(ci_verbose) \ - PATH="$(CI_INSTALL_DIR)/$2/bin:$(PATH)" \ - CI_OTP_RELEASE="$1" \ - CT_OPTS="-label $1" \ - CI_VM="$3" \ - $(MAKE) ci-setup tests - $(verbose) $(MAKE) --no-print-directory ci-extra + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests endef -$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) -$(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) -$(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) define ci_otp_target ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) $(CI_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) build git $(OTP_GIT) $(1) $(1) $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) endif endef $(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) -define ci_hipe_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$1-native),) -$(CI_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(CI_INSTALL_DIR)/$1-native -endif -endef - -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call ci_hipe_target,$(otp)))) - $(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl - $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) $(verbose) chmod +x $(KERL) help:: @@ -6070,7 +6029,7 @@ distclean-kerl: $(gen_verbose) rm -rf $(KERL) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ct apps-ct distclean-ct @@ -6078,14 +6037,11 @@ endif # Configuration. CT_OPTS ?= - ifneq ($(wildcard $(TEST_DIR)),) -ifndef CT_SUITES -CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) -endif + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= endif -CT_SUITES ?= -CT_LOGS_DIR ?= $(CURDIR)/logs # Core targets. @@ -6108,18 +6064,15 @@ CT_RUN = ct_run \ -noinput \ -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ - -logdir $(CT_LOGS_DIR) + -logdir $(CURDIR)/logs ifeq ($(CT_SUITES),) ct: $(if $(IS_APP),,apps-ct) else -# We do not run tests if we are in an apps/* with no test directory. -ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) ct: test-build $(if $(IS_APP),,apps-ct) - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif -endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target @@ -6145,16 +6098,16 @@ endif define ct_suite_target ct-$(1): test-build - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) distclean-ct: - $(gen_verbose) rm -rf $(CT_LOGS_DIR) + $(gen_verbose) rm -rf $(CURDIR)/logs/ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: plt distclean-plt dialyze @@ -6198,10 +6151,7 @@ define filter_opts.erl endef $(DIALYZER_PLT): deps app - $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ - while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) - $(verbose) dialyzer --build_plt --apps erts kernel stdlib \ - $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) plt: $(DIALYZER_PLT) @@ -6215,7 +6165,7 @@ dialyze: $(DIALYZER_PLT) endif $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-edoc edoc @@ -6223,20 +6173,10 @@ endif # Configuration. EDOC_OPTS ?= -EDOC_SRC_DIRS ?= - -define edoc.erl - SrcPaths = lists:foldl(fun(P, Acc) -> - filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc - end, [], [$(call comma_list,$(patsubst %,'%',$(EDOC_SRC_DIRS)))]), - DefaultOpts = [{source_path, SrcPaths}, {subpackages, false}], - edoc:application($(1), ".", [$(2)] ++ DefaultOpts), - halt(0). -endef # Core targets. -ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),) +ifneq ($(wildcard doc/overview.edoc),) docs:: edoc endif @@ -6245,91 +6185,30 @@ distclean:: distclean-edoc # Plugin-specific targets. edoc: distclean-edoc doc-deps - $(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS))) + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' distclean-edoc: $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info -# Copyright (c) 2013-2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# Configuration. - -DTL_FULL_PATH ?= -DTL_PATH ?= templates/ -DTL_SUFFIX ?= _dtl -DTL_OPTS ?= - -# Verbosity. - -dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); -dtl_verbose = $(dtl_verbose_$(V)) - -# Core targets. - -DTL_PATH := $(abspath $(DTL_PATH)) -DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) - -ifneq ($(DTL_FILES),) - -DTL_NAMES = $(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)) -DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) -BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) - -ifneq ($(words $(DTL_FILES)),0) -# Rebuild templates when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) - @mkdir -p $(ERLANG_MK_TMP) - @if test -f $@; then \ - touch $(DTL_FILES); \ - fi - @touch $@ - -ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl -endif - -define erlydtl_compile.erl - [begin - Module0 = case "$(strip $(DTL_FULL_PATH))" of - "" -> - filename:basename(F, ".dtl"); - _ -> - "$(DTL_PATH)/" ++ F2 = filename:rootname(F, ".dtl"), - re:replace(F2, "/", "_", [{return, list}, global]) - end, - Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), - case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of - ok -> ok; - {ok, _} -> ok - end - end || F <- string:tokens("$(1)", " ")], - halt(). -endef - -ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ - $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ - -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) - -endif - -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2014, Dave Cottlehuber +# Copyright (c) 2014 Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-escript escript escript-zip +.PHONY: distclean-escript escript # Configuration. ESCRIPT_NAME ?= $(PROJECT) ESCRIPT_FILE ?= $(ESCRIPT_NAME) -ESCRIPT_SHEBANG ?= /usr/bin/env escript ESCRIPT_COMMENT ?= This is an -*- erlang -*- file -ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME) -ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null) -ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" # Core targets. @@ -6342,28 +6221,44 @@ help:: # Plugin-specific targets. -escript-zip:: deps app - $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) - $(verbose) rm -f $(ESCRIPT_ZIP_FILE) - $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* -ifneq ($(DEPS),) - $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ - `cat $(ERLANG_MK_TMP)/deps.log | sed 's/^$(subst /,\/,$(DEPS_DIR))\///' | sed 's/$$/\/ebin\/\*/'` -endif +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef -escript:: escript-zip - $(gen_verbose) printf "%s\n" \ - "#!$(ESCRIPT_SHEBANG)" \ - "%% $(ESCRIPT_COMMENT)" \ - "%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE) - $(verbose) cat $(ESCRIPT_ZIP_FILE) >> $(ESCRIPT_FILE) - $(verbose) chmod +x $(ESCRIPT_FILE) +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) distclean-escript: - $(gen_verbose) rm -f $(ESCRIPT_FILE) + $(gen_verbose) rm -f $(ESCRIPT_NAME) -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: eunit apps-eunit @@ -6427,31 +6322,23 @@ eunit: test-build $(if $(IS_APP),,apps-eunit) ifneq ($(ALL_APPS_DIRS),) apps-eunit: - $(verbose) eunit_retcode=0 ; for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; \ - [ $$? -ne 0 ] && eunit_retcode=1 ; done ; \ - exit $$eunit_retcode + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done endif endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: relx-rel relx-relup distclean-relx-rel run +.PHONY: relx-rel distclean-relx-rel distclean-relx run # Configuration. -RELX ?= $(ERLANG_MK_TMP)/relx +RELX ?= $(CURDIR)/relx RELX_CONFIG ?= $(CURDIR)/relx.config RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel -RELX_REL_EXT ?= -RELX_TAR ?= 1 - -ifdef SFX - RELX_TAR = 1 -endif ifeq ($(firstword $(RELX_OPTS)),-o) RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) @@ -6464,12 +6351,10 @@ endif ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) rel:: relx-rel - -relup:: relx-relup endif endif -distclean:: distclean-relx-rel +distclean:: distclean-relx-rel distclean-relx # Plugin-specific targets. @@ -6478,14 +6363,14 @@ $(RELX): $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release $(if $(filter 1,$(RELX_TAR)),tar) - -relx-relup: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release relup $(if $(filter 1,$(RELX_TAR)),tar) + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) @@ -6493,28 +6378,16 @@ run: else define get_relx_release.erl - {ok, Config} = file:consult("$(call core_native_path,$(RELX_CONFIG))"), - {release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config), - Vsn = case Vsn0 of - {cmd, Cmd} -> os:cmd(Cmd); - semver -> ""; - {semver, _} -> ""; - VsnStr -> Vsn0 - end, - io:format("~s ~s", [Name, Vsn]), + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), halt(0). endef -RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) -RELX_REL_NAME := $(word 1,$(RELX_REL)) -RELX_REL_VSN := $(word 2,$(RELX_REL)) - -ifeq ($(PLATFORM),msys2) -RELX_REL_EXT := .cmd -endif +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` run: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) console + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console help:: $(verbose) printf "%s\n" "" \ @@ -6523,8 +6396,8 @@ help:: endif -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: shell @@ -6549,26 +6422,12 @@ help:: $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) build-shell-deps: $(ALL_SHELL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done shell: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) -# Copyright (c) 2017, Jean-Sébastien Pédron -# This file is contributed to erlang.mk and subject to the terms of the ISC License. - -.PHONY: show-ERL_LIBS show-ERLC_OPTS show-TEST_ERLC_OPTS - -show-ERL_LIBS: - @echo $(ERL_LIBS) - -show-ERLC_OPTS: - @$(foreach opt,$(ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -show-TEST_ERLC_OPTS: - @$(foreach opt,$(TEST_ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) @@ -6579,7 +6438,7 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl - code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), try case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); @@ -6611,7 +6470,6 @@ triq: test-build endif endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Erlang Solutions Ltd. # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6628,14 +6486,14 @@ endif XREFR ?= $(CURDIR)/xrefr export XREFR -XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/1.1.0/xrefr +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr # Core targets. help:: - $(verbose) printf '%s\n' '' \ - 'Xref targets:' \ - ' xref Run Xrefr using $$XREF_CONFIG as config file if defined' + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" distclean:: distclean-xref @@ -6651,8 +6509,7 @@ xref: deps app $(XREFR) distclean-xref: $(gen_verbose) rm -rf $(XREFR) -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2015, Viktor Söderqvist +# Copyright 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR = cover @@ -6661,7 +6518,6 @@ COVER_REPORT_DIR = cover ifdef COVER ifdef CT_RUN -ifneq ($(wildcard $(TEST_DIR)),) # All modules in 'ebin' COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) @@ -6676,7 +6532,6 @@ $(TEST_DIR)/ct.cover.spec: CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif -endif # Core targets @@ -6698,7 +6553,7 @@ help:: "Cover targets:" \ " cover-report Generate a HTML coverage report from previously collected" \ " cover data." \ - " all.coverdata Merge all coverdata files into all.coverdata." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ "" \ "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ "target tests additionally generates a HTML coverage report from the combined" \ @@ -6711,16 +6566,13 @@ COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) .PHONY: coverdata-clean coverdata-clean: - $(gen_verbose) rm -f *.coverdata $(TEST_DIR)/ct.cover.spec + $(gen_verbose) rm -f *.coverdata ct.cover.spec # Merge all coverdata files into one. -define cover_export.erl - $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) - cover:export("$@"), halt(0). -endef - all.coverdata: $(COVERDATA) - $(gen_verbose) $(call erlang,$(cover_export.erl)) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' # These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to # empty if you want the coverdata files but not the HTML report. @@ -6738,7 +6590,7 @@ else # Modules which include eunit.hrl always contain one line without coverage # because eunit defines test/0 which is never called. We compensate for this. EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ - grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) define cover_report.erl @@ -6773,71 +6625,12 @@ define cover_report.erl endef cover-report: - $(verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) $(gen_verbose) $(call erlang,$(cover_report.erl)) endif endif # ifneq ($(COVER_REPORT_DIR),) -# Copyright (c) 2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -.PHONY: sfx - -ifdef RELX_REL -ifdef SFX - -# Configuration. - -SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz -SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run - -# Core targets. - -rel:: sfx - -# Plugin-specific targets. - -define sfx_stub -#!/bin/sh - -TMPDIR=`mktemp -d` -ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0` -FILENAME=$$(basename $$0) -REL=$${FILENAME%.*} - -tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR - -$$TMPDIR/bin/$$REL console -RET=$$? - -rm -rf $$TMPDIR - -exit $$RET - -__ARCHIVE_BELOW__ -endef - -sfx: - $(call render_template,sfx_stub,$(SFX_OUTPUT_FILE)) - $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) - $(verbose) chmod +x $(SFX_OUTPUT_FILE) - -endif -endif - -# Copyright (c) 2013-2017, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# External plugins. - -DEP_PLUGINS ?= - -$(foreach p,$(DEP_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/plugins.mk,$p)))) - # Copyright (c) 2013-2015, Loïc Hoguin # Copyright (c) 2015-2016, Jean-Sébastien Pédron # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6905,20 +6698,22 @@ ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep $@ \ IS_APP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ done endif - $(verbose) set -e; for dep in $^ ; do \ + $(verbose) for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ - if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ $(MAKE) -C $$dep fetch-deps \ IS_DEP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ fi \ fi \ done diff --git a/rabbitmq-server/deps/rabbit/include/gm_specs.hrl b/deps/rabbit/include/gm_specs.hrl similarity index 94% rename from rabbitmq-server/deps/rabbit/include/gm_specs.hrl rename to deps/rabbit/include/gm_specs.hrl index c4f584e..d03f993 100644 --- a/rabbitmq-server/deps/rabbit/include/gm_specs.hrl +++ b/deps/rabbit/include/gm_specs.hrl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is Pivotal Software, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. %% -type callback_result() :: 'ok' | {'stop', any()} | {'become', atom(), args()}. diff --git a/rabbitmq-server/deps/rabbit/include/rabbit_cli.hrl b/deps/rabbit/include/rabbit_cli.hrl similarity index 97% rename from rabbitmq-server/deps/rabbit/include/rabbit_cli.hrl rename to deps/rabbit/include/rabbit_cli.hrl index 12fa5b4..53be9fc 100644 --- a/rabbitmq-server/deps/rabbit/include/rabbit_cli.hrl +++ b/deps/rabbit/include/rabbit_cli.hrl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is Pivotal Software, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. %% -define(NODE_OPT, "-n"). diff --git a/rabbitmq-server/deps/rabbit/quickcheck b/deps/rabbit/quickcheck similarity index 100% rename from rabbitmq-server/deps/rabbit/quickcheck rename to deps/rabbit/quickcheck diff --git a/rabbitmq-server/deps/rabbit/rabbitmq-components.mk b/deps/rabbit/rabbitmq-components.mk similarity index 83% rename from rabbitmq-server/deps/rabbit/rabbitmq-components.mk rename to deps/rabbit/rabbitmq-components.mk index 1e5d000..05986d8 100644 --- a/rabbitmq-server/deps/rabbit/rabbitmq-components.mk +++ b/deps/rabbit/rabbitmq-components.mk @@ -5,27 +5,6 @@ ifeq ($(.DEFAULT_GOAL),) .DEFAULT_GOAL = all endif -# PROJECT_VERSION defaults to: -# 1. the version exported by rabbitmq-server-release; -# 2. the version stored in `git-revisions.txt`, if it exists; -# 3. a version based on git-describe(1), if it is a Git clone; -# 4. 0.0.0 - -PROJECT_VERSION := $(RABBITMQ_VERSION) - -ifeq ($(PROJECT_VERSION),) -PROJECT_VERSION := $(shell \ -if test -f git-revisions.txt; then \ - head -n1 git-revisions.txt | \ - awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ -else \ - (git describe --dirty --abbrev=7 --tags --always --first-parent \ - 2>/dev/null || echo rabbitmq_v0_0_0) | \ - sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ - -e 's/-/./g'; \ -fi) -endif - # -------------------------------------------------------------------- # RabbitMQ components. # -------------------------------------------------------------------- @@ -42,17 +21,13 @@ dep_rabbit = git_rmq rabbitmq-server $(current_rmq_re dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master @@ -61,7 +36,6 @@ dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rm dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master @@ -73,11 +47,6 @@ dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(cur dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master @@ -97,41 +66,30 @@ dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(cu dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master -# Third-party dependencies version pinning. -# -# We do that in this file, which is copied in all projects, to ensure -# all projects use the same versions. It avoids conflicts and makes it -# possible to work with rabbitmq-public-umbrella. - -dep_cowboy_commit = 1.0.4 -dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2 -# Last commit of PropEr supporting Erlang R16B03. -dep_proper_commit = 735d972758d8bd85b12483626fe1b66450d6a6fe -dep_ranch_commit = 1.3.2 -# Last commit of sockjs support Erlang R16B03 and 17.x. -dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 5af2b588c812c318b19bc105b577a759c71c3e0a -dep_webmachine_commit = 1.10.8p2 +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 RABBITMQ_COMPONENTS = amqp_client \ rabbit \ rabbit_common \ rabbitmq_amqp1_0 \ rabbitmq_auth_backend_amqp \ - rabbitmq_auth_backend_cache \ rabbitmq_auth_backend_http \ rabbitmq_auth_backend_ldap \ rabbitmq_auth_mechanism_ssl \ - rabbitmq_aws \ rabbitmq_boot_steps_visualiser \ rabbitmq_clusterer \ - rabbitmq_cli \ rabbitmq_codegen \ rabbitmq_consistent_hash_exchange \ - rabbitmq_ct_client_helpers \ rabbitmq_ct_helpers \ rabbitmq_delayed_message_exchange \ rabbitmq_dotnet_client \ @@ -140,7 +98,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_federation_management \ rabbitmq_java_client \ rabbitmq_jms_client \ - rabbitmq_jms_cts \ rabbitmq_jms_topic_exchange \ rabbitmq_lvc \ rabbitmq_management \ @@ -152,11 +109,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_metronome \ rabbitmq_mqtt \ rabbitmq_objc_client \ - rabbitmq_peer_discovery_aws \ - rabbitmq_peer_discovery_common \ - rabbitmq_peer_discovery_consul \ - rabbitmq_peer_discovery_etcd \ - rabbitmq_peer_discovery_k8s \ rabbitmq_recent_history_exchange \ rabbitmq_routing_node_stamp \ rabbitmq_rtopic_exchange \ diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-defaults b/deps/rabbit/scripts/rabbitmq-defaults similarity index 76% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-defaults rename to deps/rabbit/scripts/rabbitmq-defaults index 4becba8..baffce8 100755 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-defaults +++ b/deps/rabbit/scripts/rabbitmq-defaults @@ -41,15 +41,4 @@ ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins PLUGINS_DIR="${RABBITMQ_HOME}/plugins" -# RABBIT_HOME can contain a version number, so default plugins -# directory can be hard to find if we want to package some plugin -# separately. When RABBITMQ_HOME points to a standard location where -# it's usually being installed by package managers, we add -# "/usr/lib/rabbitmq/plugins" to plugin search path. -case "$RABBITMQ_HOME" in - /usr/lib/rabbitmq/*) - PLUGINS_DIR="/usr/lib/rabbitmq/plugins:$PLUGINS_DIR" - ;; -esac - CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-defaults.bat b/deps/rabbit/scripts/rabbitmq-defaults.bat similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-defaults.bat rename to deps/rabbit/scripts/rabbitmq-defaults.bat diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-echopid.bat b/deps/rabbit/scripts/rabbitmq-echopid.bat similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-echopid.bat rename to deps/rabbit/scripts/rabbitmq-echopid.bat diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-env b/deps/rabbit/scripts/rabbitmq-env similarity index 94% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-env rename to deps/rabbit/scripts/rabbitmq-env index 52fb403..8c33e7c 100755 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-env +++ b/deps/rabbit/scripts/rabbitmq-env @@ -57,20 +57,6 @@ rmq_realpath() { fi } -path_contains_existing_directory() { - local path="${1:?}" - local dir - local rc - local IFS=" - " - for dir in $(echo "$path" | tr ':' '\n'); do - if [ -d "$dir" ]; then - return 0 - fi - done - return 1 -} - RABBITMQ_HOME="$(rmq_realpath "${RABBITMQ_SCRIPTS_DIR}/..")" ## Set defaults @@ -79,7 +65,7 @@ RABBITMQ_HOME="$(rmq_realpath "${RABBITMQ_SCRIPTS_DIR}/..")" DEFAULT_SCHEDULER_BIND_TYPE="db" [ "x" = "x$RABBITMQ_SCHEDULER_BIND_TYPE" ] && RABBITMQ_SCHEDULER_BIND_TYPE=${DEFAULT_SCHEDULER_BIND_TYPE} -DEFAULT_DISTRIBUTION_BUFFER_SIZE=128000 +DEFAULT_DISTRIBUTION_BUFFER_SIZE=32000 [ "x" = "x$RABBITMQ_DISTRIBUTION_BUFFER_SIZE" ] && RABBITMQ_DISTRIBUTION_BUFFER_SIZE=${DEFAULT_DISTRIBUTION_BUFFER_SIZE} ## Common defaults @@ -121,9 +107,8 @@ fi rmq_normalize_path() { local path=$1 - # Remove redundant slashes and strip a trailing slash for a - # PATH-like vars - ':' is the delimiter - echo "$path" | sed -e 's#/\{2,\}#/#g' -e 's#/$##' -e 's#/:#:#g' + # Remove redundant slashes and strip a trailing slash + echo "$path" | sed -e 's#/\{2,\}#/#g' -e 's#/$##' } rmq_normalize_path_var() { @@ -281,7 +266,7 @@ if [ "${RABBITMQ_DEV_ENV}" ]; then fi fi - if path_contains_existing_directory "${RABBITMQ_PLUGINS_DIR}" ; then + if [ -d "${RABBITMQ_PLUGINS_DIR}" ]; then # RabbitMQ was started with "make run-broker" from its own # source tree. Take rabbit_common from the plugins directory. ERL_LIBS="${RABBITMQ_PLUGINS_DIR}:${ERL_LIBS}" @@ -305,7 +290,7 @@ if [ "${RABBITMQ_DEV_ENV}" ]; then ERL_LIBS="${DEPS_DIR_norm}:${ERL_LIBS}" fi else - if path_contains_existing_directory "${RABBITMQ_PLUGINS_DIR}" ; then + if [ -d "${RABBITMQ_PLUGINS_DIR}" ]; then # RabbitMQ was started from its install directory. Take # rabbit_common from the plugins directory. ERL_LIBS="${RABBITMQ_PLUGINS_DIR}:${ERL_LIBS}" diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-env.bat b/deps/rabbit/scripts/rabbitmq-env.bat similarity index 95% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-env.bat rename to deps/rabbit/scripts/rabbitmq-env.bat index fcfab5e..3c84351 100644 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-env.bat +++ b/deps/rabbit/scripts/rabbitmq-env.bat @@ -38,10 +38,10 @@ if "!RABBITMQ_SCHEDULER_BIND_TYPE!"=="" ( set RABBITMQ_SCHEDULER_BIND_TYPE=!DEFAULT_SCHEDULER_BIND_TYPE! ) -REM DEFAULT_DISTRIBUTION_BUFFER_SIZE=128000 +REM DEFAULT_DISTRIBUTION_BUFFER_SIZE=32000 REM set the VM distribution buffer size REM [ "x" = "x$RABBITMQ_DISTRIBUTION_BUFFER_SIZE" ] && RABBITMQ_DISTRIBUTION_BUFFER_SIZE=${DEFAULT_DISTRIBUTION_BUFFER_SIZE} -set DEFAULT_DISTRIBUTION_BUFFER_SIZE=128000 +set DEFAULT_DISTRIBUTION_BUFFER_SIZE=32000 if "!RABBITMQ_DISTRIBUTION_BUFFER_SIZE!"=="" ( set RABBITMQ_DISTRIBUTION_BUFFER_SIZE=!DEFAULT_DISTRIBUTION_BUFFER_SIZE! ) @@ -406,12 +406,7 @@ set paths= exit /b :filter_path -REM Ensure ERL_LIBS begins with valid path -IF "%ERL_LIBS%"=="" ( - set ERL_LIBS=%~dps1%~n1%~x1 -) else ( - set ERL_LIBS=%ERL_LIBS%;%~dps1%~n1%~x1 -) +set ERL_LIBS=%ERL_LIBS%;%~dps1%~n1%~x1 exit /b :filter_paths_done diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-plugins b/deps/rabbit/scripts/rabbitmq-plugins similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-plugins rename to deps/rabbit/scripts/rabbitmq-plugins diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-plugins.bat b/deps/rabbit/scripts/rabbitmq-plugins.bat similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-plugins.bat rename to deps/rabbit/scripts/rabbitmq-plugins.bat diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-server b/deps/rabbit/scripts/rabbitmq-server similarity index 82% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-server rename to deps/rabbit/scripts/rabbitmq-server index 4d6dc3f..7b0599e 100755 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-server +++ b/deps/rabbit/scripts/rabbitmq-server @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/sh -e ## The contents of this file are subject to the Mozilla Public License ## Version 1.1 (the "License"); you may not use this file except in ## compliance with the License. You may obtain a copy of the License @@ -12,11 +12,9 @@ ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. -## Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +## Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. ## -set -e - # Get default settings with user overrides for (RABBITMQ_) # Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env @@ -108,7 +106,7 @@ RABBITMQ_LISTEN_ARG= [ "x" != "x$RABBITMQ_NODE_PORT" ] && [ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_LISTEN_ARG="-rabbit tcp_listeners [{\""${RABBITMQ_NODE_IP_ADDRESS}"\","${RABBITMQ_NODE_PORT}"}]" # If $RABBITMQ_LOGS is '-', send all log messages to stdout. Likewise -# for RABBITMQ_SASL_LOGS. This is particularly useful for Docker +# for RABBITMQ_SASL_LOGS. This is particularily useful for Docker # images. if [ "$RABBITMQ_LOGS" = '-' ]; then @@ -125,11 +123,6 @@ else RABBIT_SASL_ERROR_LOGGER='{file,"'${RABBITMQ_SASL_LOGS}'"}' fi -# Bump ETS table limit to 50000 -if [ "x" = "x$ERL_MAX_ETS_TABLES" ]; then - ERL_MAX_ETS_TABLES=50000 -fi - # we need to turn off path expansion because some of the vars, notably # RABBITMQ_SERVER_ERL_ARGS, contain terms that look like globs and # there is no other way of preventing their expansion. @@ -158,7 +151,6 @@ start_rabbitmq_server() { ensure_thread_pool_size check_start_params && RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ - ERL_MAX_ETS_TABLES=$ERL_MAX_ETS_TABLES \ exec ${ERL_DIR}erl \ -pa ${RABBITMQ_SERVER_CODE_PATH} ${RABBITMQ_EBIN_ROOT} \ ${RABBITMQ_START_RABBIT} \ @@ -235,38 +227,21 @@ else # The Erlang VM should ignore SIGINT. RABBITMQ_SERVER_START_ARGS="${RABBITMQ_SERVER_START_ARGS} ${RABBITMQ_IGNORE_SIGINT_FLAG}" - # Signal handlers. They all stop RabbitMQ properly, using - # rabbitmqctl stop. This script will exit with different exit codes: + # Signal handlers. They all stop RabbitMQ properly (using + # rabbitmqctl stop). Depending on the signal, this script will exit + # with a non-zero error code: # SIGHUP SIGTERM SIGTSTP - # Exits 0 since this is considered a normal process termination. + # They are considered a normal process termination, so the script + # exits with 0. # SIGINT - # Exits 128 + $signal_number where $signal_number is 2 for SIGINT (see - # http://pubs.opengroup.org/onlinepubs/009695399/utilities/kill.html). - # This is considered an abnormal process termination. Normally, we - # don't need to specify this exit code because the shell propagates it. - # Unfortunately, the signal handler doesn't work as expected in Dash, - # thus we need to explicitely restate the exit code. + # They are considered an abnormal process termination, the script + # exits with the job exit code. trap "stop_rabbitmq_server; exit 0" HUP TERM TSTP - trap "stop_rabbitmq_server; exit 130" INT + trap "stop_rabbitmq_server" INT start_rabbitmq_server "$@" & - rabbitmq_server_pid=$! # Block until RabbitMQ exits or a signal is caught. # Waits for last command (which is start_rabbitmq_server) - # - # The "|| true" is here to work around an issue with Dash. Normally - # in a Bourne shell, if `wait` is interrupted by a signal, the - # signal handlers defined above are executed and the script - # terminates with the exit code of `wait` (unless the signal handler - # overrides that). - # In the case of Dash, it looks like `set -e` (set at the beginning - # of this script) gets precedence over signal handling. Therefore, - # when `wait` is interrupted, its exit code is non-zero and because - # of `set -e`, the script terminates immediately without running the - # signal handler. To work around this issue, we use "|| true" to - # force that statement to succeed and the signal handler to properly - # execute. Because the statement below has an exit code of 0, the - # signal handler has to restate the expected exit code. - wait $rabbitmq_server_pid || true + wait $! fi diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-server.bat b/deps/rabbit/scripts/rabbitmq-server.bat similarity index 92% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-server.bat rename to deps/rabbit/scripts/rabbitmq-server.bat index 32c6553..585a830 100644 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-server.bat +++ b/deps/rabbit/scripts/rabbitmq-server.bat @@ -72,7 +72,7 @@ if not "!RABBITMQ_NODE_IP_ADDRESS!"=="" ( ) REM If $RABBITMQ_LOGS is '-', send all log messages to stdout. Likewise -REM for RABBITMQ_SASL_LOGS. This is particularly useful for Docker +REM for RABBITMQ_SASL_LOGS. This is particularily useful for Docker REM images. if "!RABBITMQ_LOGS!" == "-" ( @@ -99,15 +99,11 @@ if "!RABBITMQ_NODE_ONLY!"=="" ( if "!RABBITMQ_IO_THREAD_POOL_SIZE!"=="" ( set RABBITMQ_IO_THREAD_POOL_SIZE=64 -) +) -rem Bump ETS table limit to 50000 -if "!ERL_MAX_ETS_TABLES!"=="" ( - set ERL_MAX_ETS_TABLES=50000 -) set ENV_OK=true -CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE! +CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE! CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE! CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME! @@ -149,7 +145,7 @@ EXIT /B 0 if "%~2"=="" ( ECHO "Error: ENV variable should be defined: %1. Please check rabbitmq-env and rabbitmq-defaults, and !RABBITMQ_CONF_ENV_FILE! script files. Check also your Environment Variables settings" set ENV_OK=false - EXIT /B 78 + EXIT /B 78 ) EXIT /B 0 diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-service.bat b/deps/rabbit/scripts/rabbitmq-service.bat similarity index 89% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmq-service.bat rename to deps/rabbit/scripts/rabbitmq-service.bat index 47f1755..f8a8d5a 100644 --- a/rabbitmq-server/deps/rabbit/scripts/rabbitmq-service.bat +++ b/deps/rabbit/scripts/rabbitmq-service.bat @@ -76,8 +76,7 @@ if not exist "!ERLANG_SERVICE_MANAGER_PATH!\erlsrv.exe" ( ) if "!P1!" == "install" goto INSTALL_SERVICE -for %%i in (start stop) do if "%%i" == "!P1!" goto START_STOP_SERVICE -for %%i in (disable enable list remove) do if "%%i" == "!P1!" goto MODIFY_SERVICE +for %%i in (start stop disable enable list remove) do if "%%i" == "!P1!" goto MODIFY_SERVICE echo. echo ********************* @@ -106,7 +105,7 @@ if not exist "!RABBITMQ_BASE!" ( ) set ENV_OK=true -CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE! +CALL :check_not_empty "RABBITMQ_BOOT_MODULE" !RABBITMQ_BOOT_MODULE! CALL :check_not_empty "RABBITMQ_NAME_TYPE" !RABBITMQ_NAME_TYPE! CALL :check_not_empty "RABBITMQ_NODENAME" !RABBITMQ_NODENAME! @@ -174,11 +173,6 @@ if "!RABBITMQ_SERVICE_RESTART!"=="" ( set RABBITMQ_SERVICE_RESTART=restart ) -rem Bump ETS table limit to 50000 -if "!ERL_MAX_ETS_TABLES!"=="" ( - set ERL_MAX_ETS_TABLES=50000 -) - set ERLANG_SERVICE_ARGUMENTS= ^ -pa "!RABBITMQ_EBIN_ROOT!" ^ -boot start_sasl ^ @@ -216,7 +210,6 @@ set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"! -machine "!ERLANG_SERVICE_MANAGER_PATH!\erl.exe" ^ -env ERL_CRASH_DUMP="!RABBITMQ_BASE:\=/!/erl_crash.dump" ^ -env ERL_LIBS="!ERL_LIBS!" ^ --env ERL_MAX_ETS_TABLES="!ERL_MAX_ETS_TABLES!" ^ -workdir "!RABBITMQ_BASE!" ^ -stopaction "rabbit:stop_and_halt()." ^ !RABBITMQ_NAME_TYPE! !RABBITMQ_NODENAME! ^ @@ -224,30 +217,15 @@ set ERLANG_SERVICE_ARGUMENTS=!ERLANG_SERVICE_ARGUMENTS:"=\"! -comment "Multi-protocol open source messaging broker" ^ -args "!ERLANG_SERVICE_ARGUMENTS!" > NUL -if ERRORLEVEL 1 ( - EXIT /B 1 -) goto END :MODIFY_SERVICE "!ERLANG_SERVICE_MANAGER_PATH!\erlsrv" !P1! !RABBITMQ_SERVICENAME! -if ERRORLEVEL 1 ( - EXIT /B 1 -) goto END -:START_STOP_SERVICE - -REM start and stop via erlsrv reports no error message. Using net instead -net !P1! !RABBITMQ_SERVICENAME! -if ERRORLEVEL 1 ( - EXIT /B 1 -) -goto END - :END EXIT /B 0 @@ -256,7 +234,7 @@ EXIT /B 0 if "%~2"=="" ( ECHO "Error: ENV variable should be defined: %1. Please check rabbitmq-env, rabbitmq-default, and !RABBITMQ_CONF_ENV_FILE! script files. Check also your Environment Variables settings" set ENV_OK=false - EXIT /B 78 + EXIT /B 78 ) EXIT /B 0 diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmqctl b/deps/rabbit/scripts/rabbitmqctl similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmqctl rename to deps/rabbit/scripts/rabbitmqctl diff --git a/rabbitmq-server/deps/rabbit/scripts/rabbitmqctl.bat b/deps/rabbit/scripts/rabbitmqctl.bat similarity index 100% rename from rabbitmq-server/deps/rabbit/scripts/rabbitmqctl.bat rename to deps/rabbit/scripts/rabbitmqctl.bat diff --git a/rabbitmq-server/deps/rabbit/src/background_gc.erl b/deps/rabbit/src/background_gc.erl similarity index 74% rename from rabbitmq-server/deps/rabbit/src/background_gc.erl rename to deps/rabbit/src/background_gc.erl index bbac313..2986f35 100644 --- a/rabbitmq-server/deps/rabbit/src/background_gc.erl +++ b/deps/rabbit/src/background_gc.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(background_gc). @@ -25,6 +25,7 @@ terminate/2, code_change/3]). -define(MAX_RATIO, 0.01). +-define(IDEAL_INTERVAL, 60000). -define(MAX_INTERVAL, 240000). -record(state, {last_interval}). @@ -44,9 +45,7 @@ run() -> gen_server2:cast(?MODULE, run). %%---------------------------------------------------------------------------- -init([]) -> - {ok, IdealInterval} = application:get_env(rabbit, background_gc_target_interval), - {ok, interval_gc(#state{last_interval = IdealInterval})}. +init([]) -> {ok, interval_gc(#state{last_interval = ?IDEAL_INTERVAL})}. handle_call(Msg, _From, State) -> {stop, {unexpected_call, Msg}, {unexpected_call, Msg}, State}. @@ -66,22 +65,14 @@ terminate(_Reason, State) -> State. %%---------------------------------------------------------------------------- interval_gc(State = #state{last_interval = LastInterval}) -> - {ok, IdealInterval} = application:get_env(rabbit, background_gc_target_interval), {ok, Interval} = rabbit_misc:interval_operation( {?MODULE, gc, []}, - ?MAX_RATIO, ?MAX_INTERVAL, IdealInterval, LastInterval), + ?MAX_RATIO, ?MAX_INTERVAL, ?IDEAL_INTERVAL, LastInterval), erlang:send_after(Interval, self(), run), State#state{last_interval = Interval}. gc() -> - Enabled = rabbit_misc:get_env(rabbit, background_gc_enabled, false), - case Enabled of - true -> - [garbage_collect(P) || P <- processes(), - {status, waiting} == process_info(P, status)], - %% since we will never be waiting... - garbage_collect(); - false -> - ok - end, + [garbage_collect(P) || P <- processes(), + {status, waiting} == process_info(P, status)], + garbage_collect(), %% since we will never be waiting... ok. diff --git a/rabbitmq-server/deps/rabbit_common/src/delegate.erl b/deps/rabbit/src/delegate.erl similarity index 72% rename from rabbitmq-server/deps/rabbit_common/src/delegate.erl rename to deps/rabbit/src/delegate.erl index a3ae2ed..778137c 100644 --- a/rabbitmq-server/deps/rabbit_common/src/delegate.erl +++ b/deps/rabbit/src/delegate.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(delegate). @@ -47,9 +47,8 @@ -behaviour(gen_server2). --export([start_link/1, start_link/2,invoke_no_result/2, invoke_no_result/3, - invoke/2, invoke/3, monitor/2, monitor/3, demonitor/1, - call/2, cast/2, call/3, cast/3]). +-export([start_link/1, invoke_no_result/2, invoke/2, + monitor/2, demonitor/1, call/2, cast/2]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -81,38 +80,31 @@ -define(HIBERNATE_AFTER_MIN, 1000). -define(DESIRED_HIBERNATE, 10000). --define(DEFAULT_NAME, "delegate_"). %%---------------------------------------------------------------------------- start_link(Num) -> - start_link(?DEFAULT_NAME, Num). + Name = delegate_name(Num), + gen_server2:start_link({local, Name}, ?MODULE, [Name], []). -start_link(Name, Num) -> - Name1 = delegate_name(Name, Num), - gen_server2:start_link({local, Name1}, ?MODULE, [Name1], []). - -invoke(Pid, FunOrMFA) -> - invoke(Pid, ?DEFAULT_NAME, FunOrMFA). - -invoke(Pid, _Name, FunOrMFA) when is_pid(Pid) andalso node(Pid) =:= node() -> +invoke(Pid, FunOrMFA) when is_pid(Pid) andalso node(Pid) =:= node() -> apply1(FunOrMFA, Pid); -invoke(Pid, Name, FunOrMFA) when is_pid(Pid) -> - case invoke([Pid], Name, FunOrMFA) of +invoke(Pid, FunOrMFA) when is_pid(Pid) -> + case invoke([Pid], FunOrMFA) of {[{Pid, Result}], []} -> Result; {[], [{Pid, {Class, Reason, StackTrace}}]} -> erlang:raise(Class, Reason, StackTrace) end; -invoke([], _Name, _FunOrMFA) -> %% optimisation +invoke([], _FunOrMFA) -> %% optimisation {[], []}; -invoke([Pid], _Name, FunOrMFA) when node(Pid) =:= node() -> %% optimisation +invoke([Pid], FunOrMFA) when node(Pid) =:= node() -> %% optimisation case safe_invoke(Pid, FunOrMFA) of {ok, _, Result} -> {[{Pid, Result}], []}; {error, _, Error} -> {[], [{Pid, Error}]} end; -invoke(Pids, Name, FunOrMFA) when is_list(Pids) -> +invoke(Pids, FunOrMFA) when is_list(Pids) -> {LocalPids, Grouped} = group_pids_by_node(Pids), %% The use of multi_call is only safe because the timeout is %% infinity, and thus there is no process spawned in order to do @@ -121,7 +113,7 @@ invoke(Pids, Name, FunOrMFA) when is_list(Pids) -> case orddict:fetch_keys(Grouped) of [] -> {[], []}; RemoteNodes -> gen_server2:multi_call( - RemoteNodes, delegate(self(), Name, RemoteNodes), + RemoteNodes, delegate(self(), RemoteNodes), {invoke, FunOrMFA, Grouped}, infinity) end, BadPids = [{Pid, {exit, {nodedown, BadNode}, []}} || @@ -134,43 +126,32 @@ invoke(Pids, Name, FunOrMFA) when is_list(Pids) -> ({error, Pid, Error}, {Good, Bad}) -> {Good, [{Pid, Error} | Bad]} end, {[], BadPids}, ResultsNoNode). -invoke_no_result(Pid, FunOrMFA) -> - invoke_no_result(Pid, ?DEFAULT_NAME, FunOrMFA). - -invoke_no_result(Pid, _Name, FunOrMFA) when is_pid(Pid) andalso node(Pid) =:= node() -> +invoke_no_result(Pid, FunOrMFA) when is_pid(Pid) andalso node(Pid) =:= node() -> _ = safe_invoke(Pid, FunOrMFA), %% we don't care about any error ok; -invoke_no_result(Pid, Name, FunOrMFA) when is_pid(Pid) -> - invoke_no_result([Pid], Name, FunOrMFA); +invoke_no_result(Pid, FunOrMFA) when is_pid(Pid) -> + invoke_no_result([Pid], FunOrMFA); -invoke_no_result([], _Name, _FunOrMFA) -> %% optimisation +invoke_no_result([], _FunOrMFA) -> %% optimisation ok; -invoke_no_result([Pid], _Name, FunOrMFA) when node(Pid) =:= node() -> %% optimisation +invoke_no_result([Pid], FunOrMFA) when node(Pid) =:= node() -> %% optimisation _ = safe_invoke(Pid, FunOrMFA), %% must not die ok; -invoke_no_result([Pid], Name, FunOrMFA) -> - RemoteNode = node(Pid), - gen_server2:abcast([RemoteNode], delegate(self(), Name, [RemoteNode]), - {invoke, FunOrMFA, orddict:from_list([{RemoteNode, [Pid]}])}), - ok; -invoke_no_result(Pids, Name, FunOrMFA) when is_list(Pids) -> +invoke_no_result(Pids, FunOrMFA) when is_list(Pids) -> {LocalPids, Grouped} = group_pids_by_node(Pids), case orddict:fetch_keys(Grouped) of [] -> ok; RemoteNodes -> gen_server2:abcast( - RemoteNodes, delegate(self(), Name, RemoteNodes), + RemoteNodes, delegate(self(), RemoteNodes), {invoke, FunOrMFA, Grouped}) end, _ = safe_invoke(LocalPids, FunOrMFA), %% must not die ok. -monitor(process, Pid) -> - ?MODULE:monitor(process, Pid, ?DEFAULT_NAME). - -monitor(process, Pid, _Prefix) when node(Pid) =:= node() -> +monitor(process, Pid) when node(Pid) =:= node() -> erlang:monitor(process, Pid); -monitor(process, Pid, Prefix) -> - Name = delegate(Pid, Prefix, [node(Pid)]), +monitor(process, Pid) -> + Name = delegate(Pid, [node(Pid)]), gen_server2:cast(Name, {monitor, self(), Pid}), {Name, Pid}. @@ -179,36 +160,11 @@ demonitor(Ref) when is_reference(Ref) -> demonitor({Name, Pid}) -> gen_server2:cast(Name, {demonitor, self(), Pid}). -call(PidOrPids, Name, Msg) -> - invoke(PidOrPids, Name, {gen_server2, call, [Msg, infinity]}). - call(PidOrPids, Msg) -> - %% Optimization, avoids calling delegate:call/3 - invoke(PidOrPids, ?DEFAULT_NAME, {gen_server2, call, [Msg, infinity]}). - -cast(Pid, Msg) when is_pid(Pid) andalso node(Pid) =:= node() -> - %% Optimization, avoids calling invoke_no_result/3. - %% - %% This may seem like a cosmetic change at first but it actually massively reduces the memory usage in mirrored - %% queues when ack/nack are sent to the node that hosts a mirror. - %% This way binary references are not kept around unnecessarily. - %% - %% See https://github.com/rabbitmq/rabbitmq-common/issues/208#issuecomment-311308583 for a before/after - %% comparison. - _ = safe_invoke(Pid, {gen_server2, cast, [Msg]}), %% we don't care about any error - ok; -cast(Pid, Msg) when is_pid(Pid) -> - %% Optimization, avoids calling invoke_no_result/3 - RemoteNode = node(Pid), - gen_server2:abcast([RemoteNode], delegate(self(), ?DEFAULT_NAME, [RemoteNode]), - {invoke, {gen_server2, cast, [Msg]}, - orddict:from_list([{RemoteNode, [Pid]}])}), - ok; -cast(PidOrPids, Msg) -> - invoke_no_result(PidOrPids, ?DEFAULT_NAME, {gen_server2, cast, [Msg]}). + invoke(PidOrPids, {gen_server2, call, [Msg, infinity]}). -cast(PidOrPids, Name, Msg) -> - invoke_no_result(PidOrPids, Name, {gen_server2, cast, [Msg]}). +cast(PidOrPids, Msg) -> + invoke_no_result(PidOrPids, {gen_server2, cast, [Msg]}). %%---------------------------------------------------------------------------- @@ -223,14 +179,14 @@ group_pids_by_node(Pids) -> node(Pid), fun (List) -> [Pid | List] end, [Pid], Remote)} end, {[], orddict:new()}, Pids). -delegate_name(Name, Hash) -> - list_to_atom(Name ++ integer_to_list(Hash)). +delegate_name(Hash) -> + list_to_atom("delegate_" ++ integer_to_list(Hash)). -delegate(Pid, Prefix, RemoteNodes) -> +delegate(Pid, RemoteNodes) -> case get(delegate) of - undefined -> Name = delegate_name(Prefix, + undefined -> Name = delegate_name( erlang:phash2(Pid, - delegate_sup:count(RemoteNodes, Prefix))), + delegate_sup:count(RemoteNodes))), put(delegate, Name), Name; Name -> Name diff --git a/rabbitmq-server/deps/rabbit_common/src/delegate_sup.erl b/deps/rabbit/src/delegate_sup.erl similarity index 65% rename from rabbitmq-server/deps/rabbit_common/src/delegate_sup.erl rename to deps/rabbit/src/delegate_sup.erl index 38dccd6..ba0964f 100644 --- a/rabbitmq-server/deps/rabbit_common/src/delegate_sup.erl +++ b/deps/rabbit/src/delegate_sup.erl @@ -11,54 +11,45 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(delegate_sup). -behaviour(supervisor). --export([start_link/1, start_link/2, count/1, count/2, sup_name/1]). +-export([start_link/1, count/1]). -export([init/1]). --define(SERVER, "delegate_"). +-define(SERVER, ?MODULE). %%---------------------------------------------------------------------------- -spec start_link(integer()) -> rabbit_types:ok_pid_or_error(). --spec start_link(integer(), string()) -> rabbit_types:ok_pid_or_error(). -spec count([node()]) -> integer(). %%---------------------------------------------------------------------------- -sup_name(Prefix) -> - list_to_atom(Prefix ++ "sup"). - -start_link(Count, Prefix) -> - supervisor:start_link({local, sup_name(Prefix)}, ?MODULE, [Count, Prefix]). start_link(Count) -> - start_link(Count, ?SERVER). - -count(Nodes) -> - count(Nodes, ?SERVER). + supervisor:start_link({local, ?SERVER}, ?MODULE, [Count]). -count([], _) -> +count([]) -> 1; -count([Node | Nodes], Prefix) -> +count([Node | Nodes]) -> try - length(supervisor:which_children({sup_name(Prefix), Node})) + length(supervisor:which_children({?SERVER, Node})) catch exit:{{R, _}, _} when R =:= nodedown; R =:= shutdown -> - count(Nodes, Prefix); + count(Nodes); exit:{R, _} when R =:= noproc; R =:= normal; R =:= shutdown; R =:= nodedown -> - count(Nodes, Prefix) + count(Nodes) end. %%---------------------------------------------------------------------------- -init([Count, Name]) -> +init([Count]) -> {ok, {{one_for_one, 10, 10}, - [{Num, {delegate, start_link, [Name, Num]}, + [{Num, {delegate, start_link, [Num]}, transient, 16#ffffffff, worker, [delegate]} || Num <- lists:seq(0, Count - 1)]}}. diff --git a/rabbitmq-server/deps/rabbit/src/dtree.erl b/deps/rabbit/src/dtree.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/dtree.erl rename to deps/rabbit/src/dtree.erl index 466ec88..a2232c0 100644 --- a/rabbitmq-server/deps/rabbit/src/dtree.erl +++ b/deps/rabbit/src/dtree.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% A dual-index tree. diff --git a/rabbitmq-server/deps/rabbit_common/src/file_handle_cache.erl b/deps/rabbit/src/file_handle_cache.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/file_handle_cache.erl rename to deps/rabbit/src/file_handle_cache.erl index af51718..e4af1e8 100644 --- a/rabbitmq-server/deps/rabbit_common/src/file_handle_cache.erl +++ b/deps/rabbit/src/file_handle_cache.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(file_handle_cache). @@ -149,7 +149,7 @@ open_with_absolute_path/3]). -export([obtain/0, obtain/1, release/0, release/1, transfer/1, transfer/2, set_limit/1, get_limit/0, info_keys/0, with_handle/1, with_handle/2, - info/0, info/1, clear_read_cache/0, clear_process_read_cache/0]). + info/0, info/1, clear_read_cache/0]). -export([ulimit/0]). -export([start_link/0, start_link/2, init/1, handle_call/3, handle_cast/2, @@ -165,6 +165,8 @@ -define(CLIENT_ETS_TABLE, file_handle_cache_client). -define(ELDERS_ETS_TABLE, file_handle_cache_elders). +-include("rabbit.hrl"). % For #amqqueue record definition. + %%---------------------------------------------------------------------------- -record(file, @@ -599,7 +601,35 @@ info() -> info(?INFO_KEYS). info(Items) -> gen_server2:call(?SERVER, {info, Items}, infinity). clear_read_cache() -> - gen_server2:cast(?SERVER, clear_read_cache). + case application:get_env(rabbit, fhc_read_buffering) of + {ok, true} -> + gen_server2:cast(?SERVER, clear_read_cache), + clear_vhost_read_cache(rabbit_vhost:list()); + _ -> %% undefined or {ok, false} + ok + end. + +clear_vhost_read_cache([]) -> + ok; +clear_vhost_read_cache([VHost | Rest]) -> + clear_queue_read_cache(rabbit_amqqueue:list(VHost)), + clear_vhost_read_cache(Rest). + +clear_queue_read_cache([]) -> + ok; +clear_queue_read_cache([#amqqueue{pid = MPid, slave_pids = SPids} | Rest]) -> + %% Limit the action to the current node. + Pids = [P || P <- [MPid | SPids], node(P) =:= node()], + %% This function is executed in the context of the backing queue + %% process because the read buffer is stored in the process + %% dictionary. + Fun = fun(_, State) -> + _ = clear_process_read_cache(), + State + end, + [rabbit_amqqueue:run_backing_queue(Pid, rabbit_variable_queue, Fun) + || Pid <- Pids], + clear_queue_read_cache(Rest). clear_process_read_cache() -> [ @@ -1010,7 +1040,7 @@ tune_read_buffer_limit(Handle = #handle{read_buffer = Buf, end, Lim)}. maybe_reduce_read_cache(SparedRefs) -> - case vm_memory_monitor:get_memory_use(bytes) of + case rabbit_memory_monitor:memory_use(bytes) of {_, infinity} -> ok; {MemUse, MemLimit} when MemUse < MemLimit -> ok; {MemUse, MemLimit} -> reduce_read_cache( diff --git a/rabbitmq-server/deps/rabbit_common/src/file_handle_cache_stats.erl b/deps/rabbit/src/file_handle_cache_stats.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/file_handle_cache_stats.erl rename to deps/rabbit/src/file_handle_cache_stats.erl index 13d03f0..12a78f8 100644 --- a/rabbitmq-server/deps/rabbit_common/src/file_handle_cache_stats.erl +++ b/deps/rabbit/src/file_handle_cache_stats.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(file_handle_cache_stats). diff --git a/rabbitmq-server/deps/rabbit/src/gatherer.erl b/deps/rabbit/src/gatherer.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/gatherer.erl rename to deps/rabbit/src/gatherer.erl index 7cc2824..1830269 100644 --- a/rabbitmq-server/deps/rabbit/src/gatherer.erl +++ b/deps/rabbit/src/gatherer.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(gatherer). diff --git a/rabbitmq-server/deps/rabbit/src/gm.erl b/deps/rabbit/src/gm.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/gm.erl rename to deps/rabbit/src/gm.erl index cf3e217..41aa01f 100644 --- a/rabbitmq-server/deps/rabbit/src/gm.erl +++ b/deps/rabbit/src/gm.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(gm). @@ -395,8 +395,9 @@ -define(GROUP_TABLE, gm_group). -define(MAX_BUFFER_SIZE, 100000000). %% 100MB +-define(HIBERNATE_AFTER_MIN, 1000). +-define(DESIRED_HIBERNATE, 10000). -define(BROADCAST_TIMER, 25). --define(FORCE_GC_TIMER, 250). -define(VERSION_START, 0). -define(SETS, ordsets). -define(DICT, orddict). @@ -415,7 +416,6 @@ broadcast_buffer, broadcast_buffer_sz, broadcast_timer, - force_gc_timer, txn_executor, shutting_down }). @@ -508,8 +508,7 @@ table_definitions() -> [{Name, [?TABLE_MATCH | Attributes]}]. start_link(GroupName, Module, Args, TxnFun) -> - gen_server2:start_link(?MODULE, [GroupName, Module, Args, TxnFun], - [{spawn_opt, [{fullsweep_after, 0}]}]). + gen_server2:start_link(?MODULE, [GroupName, Module, Args, TxnFun], []). leave(Server) -> gen_server2:cast(Server, leave). @@ -552,9 +551,9 @@ init([GroupName, Module, Args, TxnFun]) -> broadcast_buffer = [], broadcast_buffer_sz = 0, broadcast_timer = undefined, - force_gc_timer = undefined, txn_executor = TxnFun, - shutting_down = false }}. + shutting_down = false }, hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. handle_call({confirmed_broadcast, _Msg}, _From, @@ -709,10 +708,6 @@ handle_cast(leave, State) -> {stop, normal, State}. -handle_info(force_gc, State) -> - garbage_collect(), - noreply(State #state { force_gc_timer = undefined }); - handle_info(flush, State) -> noreply( flush_broadcast_buffer(State #state { broadcast_timer = undefined })); @@ -888,24 +883,14 @@ handle_msg({activity, _NotLeft, _Activity}, State) -> noreply(State) -> - {noreply, ensure_timers(State), flush_timeout(State)}. + {noreply, ensure_broadcast_timer(State), flush_timeout(State)}. reply(Reply, State) -> - {reply, Reply, ensure_timers(State), flush_timeout(State)}. - -ensure_timers(State) -> - ensure_force_gc_timer(ensure_broadcast_timer(State)). + {reply, Reply, ensure_broadcast_timer(State), flush_timeout(State)}. -flush_timeout(#state{broadcast_buffer = []}) -> infinity; +flush_timeout(#state{broadcast_buffer = []}) -> hibernate; flush_timeout(_) -> 0. -ensure_force_gc_timer(State = #state { force_gc_timer = TRef }) - when is_reference(TRef) -> - State; -ensure_force_gc_timer(State = #state { force_gc_timer = undefined }) -> - TRef = erlang:send_after(?FORCE_GC_TIMER, self(), force_gc), - State #state { force_gc_timer = TRef }. - ensure_broadcast_timer(State = #state { broadcast_buffer = [], broadcast_timer = undefined }) -> State; @@ -973,7 +958,8 @@ flush_broadcast_buffer(State = #state { self = Self, end, Self, MembersState), State #state { members_state = MembersState1, broadcast_buffer = [], - broadcast_buffer_sz = 0 }. + broadcast_buffer_sz = 0}. + %% --------------------------------------------------------------------------- %% View construction and inspection diff --git a/rabbitmq-server/deps/rabbit/src/lqueue.erl b/deps/rabbit/src/lqueue.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/lqueue.erl rename to deps/rabbit/src/lqueue.erl diff --git a/rabbitmq-server/deps/rabbit/src/mirrored_supervisor_sups.erl b/deps/rabbit/src/mirrored_supervisor_sups.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/mirrored_supervisor_sups.erl rename to deps/rabbit/src/mirrored_supervisor_sups.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/mnesia_sync.erl b/deps/rabbit/src/mnesia_sync.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/mnesia_sync.erl rename to deps/rabbit/src/mnesia_sync.erl index a263a4f..8d5c946 100644 --- a/rabbitmq-server/deps/rabbit_common/src/mnesia_sync.erl +++ b/deps/rabbit/src/mnesia_sync.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(mnesia_sync). diff --git a/rabbitmq-server/deps/rabbit/src/pg_local.erl b/deps/rabbit/src/pg_local.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/pg_local.erl rename to deps/rabbit/src/pg_local.erl diff --git a/deps/rabbit/src/rabbit.app.src b/deps/rabbit/src/rabbit.app.src new file mode 100644 index 0000000..fe5a4c5 --- /dev/null +++ b/deps/rabbit/src/rabbit.app.src @@ -0,0 +1,111 @@ +{application, rabbit, %% -*- erlang -*- + [{description, "RabbitMQ"}, + {id, "RabbitMQ"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, [rabbit_amqqueue_sup, + rabbit_log, + rabbit_node_monitor, + rabbit_router, + rabbit_sup, + rabbit_direct_client_sup]}, + {applications, [kernel, stdlib, sasl, mnesia, rabbit_common, ranch, os_mon, xmerl]}, +%% we also depend on crypto, public_key and ssl but they shouldn't be +%% in here as we don't actually want to start it + {mod, {rabbit, []}}, + {env, [{tcp_listeners, [5672]}, + {num_tcp_acceptors, 10}, + {ssl_listeners, []}, + {num_ssl_acceptors, 1}, + {ssl_options, []}, + {vm_memory_high_watermark, 0.4}, + {vm_memory_high_watermark_paging_ratio, 0.5}, + {memory_monitor_interval, 2500}, + {disk_free_limit, 50000000}, %% 50MB + {msg_store_index_module, rabbit_msg_store_ets_index}, + {backing_queue_module, rabbit_variable_queue}, + %% 0 ("no limit") would make a better default, but that + %% breaks the QPid Java client + {frame_max, 131072}, + {channel_max, 0}, + {heartbeat, 60}, + {msg_store_file_size_limit, 16777216}, + {fhc_write_buffering, true}, + {fhc_read_buffering, false}, + {queue_index_max_journal_entries, 32768}, + {queue_index_embed_msgs_below, 4096}, + {default_user, <<"guest">>}, + {default_pass, <<"guest">>}, + {default_user_tags, [administrator]}, + {default_vhost, <<"/">>}, + {default_permissions, [<<".*">>, <<".*">>, <<".*">>]}, + {loopback_users, [<<"guest">>]}, + {password_hashing_module, rabbit_password_hashing_sha256}, + {cluster_nodes, {[], disc}}, + {server_properties, []}, + {collect_statistics, none}, + {collect_statistics_interval, 5000}, + {mnesia_table_loading_timeout, 30000}, + {auth_mechanisms, ['PLAIN', 'AMQPLAIN']}, + {auth_backends, [rabbit_auth_backend_internal]}, + {delegate_count, 16}, + {trace_vhosts, []}, + {log_levels, [{connection, info}]}, + {ssl_cert_login_from, distinguished_name}, + {ssl_handshake_timeout, 5000}, + {ssl_allow_poodle_attack, false}, + {handshake_timeout, 10000}, + {reverse_dns_lookups, false}, + {cluster_partition_handling, ignore}, + {cluster_keepalive_interval, 10000}, + {tcp_listen_options, [{backlog, 128}, + {nodelay, true}, + {linger, {true, 0}}, + {exit_on_close, false}]}, + {halt_on_upgrade_failure, true}, + {hipe_compile, false}, + %% see bug 24513 for how this list was created + {hipe_modules, + [rabbit_reader, rabbit_channel, gen_server2, rabbit_exchange, + rabbit_command_assembler, rabbit_framing_amqp_0_9_1, rabbit_basic, + rabbit_event, lists, queue, priority_queue, rabbit_router, + rabbit_trace, rabbit_misc, rabbit_binary_parser, + rabbit_exchange_type_direct, rabbit_guid, rabbit_net, + rabbit_amqqueue_process, rabbit_variable_queue, + rabbit_binary_generator, rabbit_writer, delegate, gb_sets, lqueue, + sets, orddict, rabbit_amqqueue, rabbit_limiter, gb_trees, + rabbit_queue_index, rabbit_exchange_decorator, gen, dict, ordsets, + file_handle_cache, rabbit_msg_store, array, + rabbit_msg_store_ets_index, rabbit_msg_file, + rabbit_exchange_type_fanout, rabbit_exchange_type_topic, mnesia, + mnesia_lib, rpc, mnesia_tm, qlc, sofs, proplists, credit_flow, + pmon, ssl_connection, tls_connection, ssl_record, tls_record, + gen_fsm, ssl]}, + {ssl_apps, [asn1, crypto, public_key, ssl]}, + %% see rabbitmq-server#114 + {mirroring_flow_control, true}, + {mirroring_sync_batch_size, 4096}, + %% see rabbitmq-server#227 and related tickets. + %% msg_store_credit_disc_bound only takes effect when + %% messages are persisted to the message store. If messages + %% are embedded on the queue index, then modifying this + %% setting has no effect because credit_flow is not used when + %% writing to the queue index. See the setting + %% queue_index_embed_msgs_below above. + {msg_store_credit_disc_bound, {2000, 500}}, + {msg_store_io_batch_size, 2048}, + %% see rabbitmq-server#143 + %% and rabbitmq-server#949 + {credit_flow_default_credit, {200, 100}}, + %% see rabbitmq-server#248 + %% and rabbitmq-server#667 + {channel_operation_timeout, 15000}, + {config_entry_decoder, [ + {cipher, aes_cbc256}, + {hash, sha512}, + {iterations, 1000}, + {passphrase, undefined} + ]}, + %% rabbitmq-server-973 + {lazy_queue_explicit_gc_run_operation_threshold, 250} + ]}]}. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit.erl b/deps/rabbit/src/rabbit.erl similarity index 91% rename from rabbitmq-server/deps/rabbit/src/rabbit.erl rename to deps/rabbit/src/rabbit.erl index fbd8840..1f0df1a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit.erl +++ b/deps/rabbit/src/rabbit.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit). @@ -22,7 +22,7 @@ stop_and_halt/0, await_startup/0, status/0, is_running/0, is_running/1, environment/0, rotate_logs/1, force_event_refresh/1, start_fhc/0]). --export([start/2, stop/1]). +-export([start/2, stop/1, prep_stop/1]). -export([start_apps/1, stop_apps/1]). -export([log_location/1, config_files/0, decrypt_config/2]). %% for testing and mgmt-agent @@ -85,13 +85,6 @@ {requires, external_infrastructure}, {enables, kernel_ready}]}). --rabbit_boot_step({rabbit_core_metrics, - [{description, "core metrics storage"}, - {mfa, {rabbit_sup, start_child, - [rabbit_metrics]}}, - {requires, pre_boot}, - {enables, external_infrastructure}]}). - -rabbit_boot_step({rabbit_event, [{description, "statistics event manager"}, {mfa, {rabbit_sup, start_restartable_child, @@ -194,12 +187,6 @@ [background_gc]}}, {enables, networking}]}). --rabbit_boot_step({rabbit_core_metrics_gc, - [{description, "background core metrics garbage collection"}, - {mfa, {rabbit_sup, start_restartable_child, - [rabbit_core_metrics_gc]}}, - {enables, networking}]}). - %%--------------------------------------------------------------------------- -include("rabbit_framing.hrl"). @@ -361,16 +348,15 @@ sd_open_port() -> use_stdio, out]). sd_notify_socat(Unit) -> - try sd_open_port() of + case sd_open_port() of + {'EXIT', Exit} -> + io:format(standard_error, "Failed to start socat ~p~n", [Exit]), + false; Port -> Port ! {self(), {command, sd_notify_data()}}, Result = sd_wait_activation(Port, Unit), port_close(Port), Result - catch - Class:Reason -> - io:format(standard_error, "Failed to start socat ~p:~p~n", [Class, Reason]), - false end. sd_current_unit() -> @@ -434,37 +420,23 @@ start_it(StartFun) -> stop() -> case whereis(rabbit_boot) of undefined -> ok; - _ -> - rabbit_log:info("RabbitMQ hasn't finished starting yet. Waiting for startup to finish before stopping..."), - wait_for_boot_to_finish() + _ -> await_startup(true) end, - rabbit_log:info("RabbitMQ is asked to stop...~n", []), + rabbit_log:info("Stopping RabbitMQ~n", []), Apps = ?APPS ++ rabbit_plugins:active(), stop_apps(app_utils:app_dependency_order(Apps, true)), - rabbit_log:info("Successfully stopped RabbitMQ and its dependencies~n", []). + rabbit_log:info("Stopped RabbitMQ application~n", []). stop_and_halt() -> try stop() - catch Type:Reason -> - rabbit_log:error("Error trying to stop RabbitMQ: ~p:~p", [Type, Reason]), - error({Type, Reason}) after - %% Enclose all the logging in the try block. - %% init:stop() will be called regardless of any errors. - try - AppsLeft = [ A || {A, _, _} <- application:which_applications() ], - rabbit_log:info( - lists:flatten(["Halting Erlang VM with the following applications:~n", - [" ~p~n" || _ <- AppsLeft]]), - AppsLeft), - %% Also duplicate this information to stderr, so console where - %% foreground broker was running (or systemd journal) will - %% contain information about graceful termination. - io:format(standard_error, "Gracefully halting Erlang VM~n", []) - after - init:stop() - end + rabbit_log:info("Halting Erlang VM~n", []), + %% Also duplicate this information to stderr, so console where + %% foreground broker was running (or systemd journal) will + %% contain information about graceful termination. + io:format(standard_error, "Gracefully halting Erlang VM~n", []), + init:stop() end, ok. @@ -481,7 +453,7 @@ start_apps(Apps) -> prompt -> IoDevice = get_input_iodevice(), io:setopts(IoDevice, [{echo, false}]), - PP = rabbit_misc:lists_droplast(io:get_line(IoDevice, + PP = lists:droplast(io:get_line(IoDevice, "\nPlease enter the passphrase to unlock encrypted " "configuration entries.\n\nPassphrase: ")), io:setopts(IoDevice, [{echo, true}]), @@ -583,10 +555,6 @@ decrypt_list([Value|Tail], Algo, Acc) -> decrypt_list(Tail, Algo, [decrypt(Value, Algo)|Acc]). stop_apps(Apps) -> - rabbit_log:info( - lists:flatten(["Stopping RabbitMQ applications and their dependencies in the following order:~n", - [" ~p~n" || _ <- Apps]]), - lists:reverse(Apps)), ok = app_utils:stop_applications( Apps, handle_app_error(error_during_shutdown)), case lists:member(rabbit, Apps) of @@ -604,32 +572,19 @@ handle_app_error(Term) -> end. await_startup() -> - case is_booting() of - true -> wait_for_boot_to_finish(); - false -> - case is_running() of - true -> ok; - false -> wait_for_boot_to_start(), - wait_for_boot_to_finish() - end - end. - -is_booting() -> - whereis(rabbit_boot) /= undefined. - -wait_for_boot_to_start() -> - case whereis(rabbit_boot) of - undefined -> timer:sleep(100), - wait_for_boot_to_start(); - _ -> ok - end. + await_startup(false). -wait_for_boot_to_finish() -> +await_startup(HaveSeenRabbitBoot) -> + %% We don't take absence of rabbit_boot as evidence we've started, + %% since there's a small window before it is registered. case whereis(rabbit_boot) of - undefined -> true = is_running(), - ok; + undefined -> case HaveSeenRabbitBoot orelse is_running() of + true -> ok; + false -> timer:sleep(100), + await_startup(false) + end; _ -> timer:sleep(100), - wait_for_boot_to_finish() + await_startup(true) end. status() -> @@ -640,8 +595,7 @@ status() -> {erlang_version, erlang:system_info(system_version)}, {memory, rabbit_vm:memory()}, {alarms, alarms()}, - {listeners, listeners()}, - {vm_memory_calculation_strategy, vm_memory_monitor:get_memory_calculation_strategy()}], + {listeners, listeners()}], S2 = rabbit_misc:filter_exit_map( fun ({Key, {M, F, A}}) -> {Key, erlang:apply(M, F, A)} end, [{vm_memory_high_watermark, {vm_memory_monitor, @@ -736,7 +690,7 @@ start(normal, []) -> Error end. -stop(_State) -> +prep_stop(_State) -> ok = rabbit_alarm:stop(), ok = case rabbit_mnesia:is_clustered() of true -> ok; @@ -744,6 +698,8 @@ stop(_State) -> end, ok. +stop(_) -> ok. + -spec boot_error(term(), not_available | [tuple()]) -> no_return(). boot_error({could_not_start, rabbit, {{timeout_waiting_for_tables, _}, _}}, @@ -815,25 +771,14 @@ insert_default_data() -> {ok, DefaultVHost} = application:get_env(default_vhost), {ok, [DefaultConfigurePerm, DefaultWritePerm, DefaultReadPerm]} = application:get_env(default_permissions), - - DefaultUserBin = rabbit_data_coercion:to_binary(DefaultUser), - DefaultPassBin = rabbit_data_coercion:to_binary(DefaultPass), - DefaultVHostBin = rabbit_data_coercion:to_binary(DefaultVHost), - DefaultConfigurePermBin = rabbit_data_coercion:to_binary(DefaultConfigurePerm), - DefaultWritePermBin = rabbit_data_coercion:to_binary(DefaultWritePerm), - DefaultReadPermBin = rabbit_data_coercion:to_binary(DefaultReadPerm), - - ok = rabbit_vhost:add(DefaultVHostBin), - ok = rabbit_auth_backend_internal:add_user( - DefaultUserBin, - DefaultPassBin - ), - ok = rabbit_auth_backend_internal:set_tags(DefaultUserBin,DefaultTags), - ok = rabbit_auth_backend_internal:set_permissions(DefaultUserBin, - DefaultVHostBin, - DefaultConfigurePermBin, - DefaultWritePermBin, - DefaultReadPermBin), + ok = rabbit_vhost:add(DefaultVHost), + ok = rabbit_auth_backend_internal:add_user(DefaultUser, DefaultPass), + ok = rabbit_auth_backend_internal:set_tags(DefaultUser, DefaultTags), + ok = rabbit_auth_backend_internal:set_permissions(DefaultUser, + DefaultVHost, + DefaultConfigurePerm, + DefaultWritePerm, + DefaultReadPerm), ok. %%--------------------------------------------------------------------------- @@ -950,7 +895,7 @@ erts_version_check() -> end. print_banner() -> - {ok, Product} = application:get_key(description), + {ok, Product} = application:get_key(id), {ok, Version} = application:get_key(vsn), io:format("~n ~s ~s. ~s" "~n ## ## ~s" @@ -1165,9 +1110,9 @@ ensure_working_fhc() -> end, TestPid = spawn_link(TestFun), %% Because we are waiting for the test fun, abuse the - %% 'mnesia_table_loading_retry_timeout' parameter to find a sane timeout + %% 'mnesia_table_loading_timeout' parameter to find a sane timeout %% value. - Timeout = rabbit_table:retry_timeout(), + Timeout = rabbit_table:wait_timeout(), receive fhc_ok -> ok; {'EXIT', TestPid, Exception} -> throw({ensure_working_fhc, Exception}) diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_access_control.erl b/deps/rabbit/src/rabbit_access_control.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_access_control.erl rename to deps/rabbit/src/rabbit_access_control.erl index cf09429..3ae7d7f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_access_control.erl +++ b/deps/rabbit/src/rabbit_access_control.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_access_control). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_alarm.erl b/deps/rabbit/src/rabbit_alarm.erl similarity index 95% rename from rabbitmq-server/deps/rabbit/src/rabbit_alarm.erl rename to deps/rabbit/src/rabbit_alarm.erl index e08f77d..dd64c6f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_alarm.erl +++ b/deps/rabbit/src/rabbit_alarm.erl @@ -11,12 +11,12 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% There are two types of alarms handled by this module: %% %% * per-node resource (disk, memory) alarms for the whole cluster. If any node -%% has an alarm, then all publishing should be disabled across the +%% has an alarm, then all publishing should be disabled througout the %% cluster until all alarms clear. When a node sets such an alarm, %% this information is automatically propagated throughout the cluster. %% `#alarms.alarmed_nodes' is being used to track this type of alarms. @@ -128,12 +128,8 @@ handle_call(_Request, State) -> handle_event({set_alarm, {{resource_limit, Source, Node}, []}}, State) -> case is_node_alarmed(Source, Node, State) of - true -> - {ok, State}; - false -> - rabbit_event:notify(alarm_set, [{source, Source}, - {node, Node}]), - handle_set_resource_alarm(Source, Node, State) + true -> {ok, State}; + false -> handle_set_resource_alarm(Source, Node, State) end; handle_event({set_alarm, Alarm}, State = #alarms{alarms = Alarms}) -> case lists:member(Alarm, Alarms) of @@ -145,8 +141,6 @@ handle_event({set_alarm, Alarm}, State = #alarms{alarms = Alarms}) -> handle_event({clear_alarm, {resource_limit, Source, Node}}, State) -> case is_node_alarmed(Source, Node, State) of true -> - rabbit_event:notify(alarm_cleared, [{source, Source}, - {node, Node}]), handle_clear_resource_alarm(Source, Node, State); false -> {ok, State} diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_process.erl b/deps/rabbit/src/rabbit_amqqueue_process.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_process.erl rename to deps/rabbit/src/rabbit_amqqueue_process.erl index 16a5a70..bfa868c 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_process.erl +++ b/deps/rabbit/src/rabbit_amqqueue_process.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqqueue_process). @@ -101,14 +101,13 @@ %%---------------------------------------------------------------------------- -define(STATISTICS_KEYS, - [messages_ready, - messages_unacknowledged, - messages, - reductions, - name, + [name, policy, exclusive_consumer_pid, exclusive_consumer_tag, + messages_ready, + messages_unacknowledged, + messages, consumers, consumer_utilisation, memory, @@ -116,6 +115,7 @@ synchronised_slave_pids, recoverable_slaves, state, + reductions, garbage_collection ]). @@ -258,13 +258,11 @@ init_with_backing_queue_state(Q = #amqqueue{exclusive_owner = Owner}, BQ, BQS, State3. terminate(shutdown = R, State = #q{backing_queue = BQ}) -> - rabbit_core_metrics:queue_deleted(qname(State)), terminate_shutdown(fun (BQS) -> BQ:terminate(R, BQS) end, State); terminate({shutdown, missing_owner} = Reason, State) -> %% if the owner was missing then there will be no queue, so don't emit stats terminate_shutdown(terminate_delete(false, Reason, State), State); terminate({shutdown, _} = R, State = #q{backing_queue = BQ}) -> - rabbit_core_metrics:queue_deleted(qname(State)), terminate_shutdown(fun (BQS) -> BQ:terminate(R, BQS) end, State); terminate(normal, State) -> %% delete case terminate_shutdown(terminate_delete(true, normal, State), State); @@ -940,13 +938,9 @@ emit_stats(State) -> emit_stats(State, Extra) -> ExtraKs = [K || {K, _} <- Extra], - [{messages_ready, MR}, {messages_unacknowledged, MU}, {messages, M}, - {reductions, R}, {name, Name} | Infos] = All - = [{K, V} || {K, V} <- infos(statistics_keys(), State), - not lists:member(K, ExtraKs)], - rabbit_core_metrics:queue_stats(Name, Extra ++ Infos), - rabbit_core_metrics:queue_stats(Name, MR, MU, M, R), - rabbit_event:notify(queue_stats, Extra ++ All). + Infos = [{K, V} || {K, V} <- infos(statistics_keys(), State), + not lists:member(K, ExtraKs)], + rabbit_event:notify(queue_stats, Extra ++ Infos). emit_consumer_created(ChPid, CTag, Exclusive, AckRequired, QName, PrefetchCount, Args, Ref) -> @@ -961,7 +955,6 @@ emit_consumer_created(ChPid, CTag, Exclusive, AckRequired, QName, Ref). emit_consumer_deleted(ChPid, ConsumerTag, QName) -> - rabbit_core_metrics:consumer_deleted(ChPid, ConsumerTag, QName), rabbit_event:notify(consumer_deleted, [{consumer_tag, ConsumerTag}, {channel, ChPid}, @@ -1092,14 +1085,9 @@ handle_call({basic_consume, NoAck, ChPid, LimiterPid, LimiterActive, has_had_consumers = true, exclusive_consumer = ExclusiveConsumer}, ok = maybe_send_reply(ChPid, OkMsg), - QName = qname(State1), - AckRequired = not NoAck, - rabbit_core_metrics:consumer_created( - ChPid, ConsumerTag, ExclusiveConsume, AckRequired, QName, - PrefetchCount, Args), emit_consumer_created(ChPid, ConsumerTag, ExclusiveConsume, - AckRequired, QName, PrefetchCount, - Args, none), + not NoAck, qname(State1), + PrefetchCount, Args, none), notify_decorators(State1), reply(ok, run_message_queue(State1)) end; diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup.erl b/deps/rabbit/src/rabbit_amqqueue_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup.erl rename to deps/rabbit/src/rabbit_amqqueue_sup.erl index ed0595d..f1e770a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup.erl +++ b/deps/rabbit/src/rabbit_amqqueue_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqqueue_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup_sup.erl b/deps/rabbit/src/rabbit_amqqueue_sup_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup_sup.erl rename to deps/rabbit/src/rabbit_amqqueue_sup_sup.erl index d0c55b2..c57d933 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue_sup_sup.erl +++ b/deps/rabbit/src/rabbit_amqqueue_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqqueue_sup_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl b/deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl rename to deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl index 9016d0d..aad004a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl +++ b/deps/rabbit/src/rabbit_auth_mechanism_amqplain.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_amqplain). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl b/deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl rename to deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl index 9d42896..ed74c35 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl +++ b/deps/rabbit/src/rabbit_auth_mechanism_cr_demo.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_cr_demo). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_plain.erl b/deps/rabbit/src/rabbit_auth_mechanism_plain.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_plain.erl rename to deps/rabbit/src/rabbit_auth_mechanism_plain.erl index 7a34b0a..4313196 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_auth_mechanism_plain.erl +++ b/deps/rabbit/src/rabbit_auth_mechanism_plain.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_plain). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_autoheal.erl b/deps/rabbit/src/rabbit_autoheal.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_autoheal.erl rename to deps/rabbit/src/rabbit_autoheal.erl index 58f60bb..3adcc09 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_autoheal.erl +++ b/deps/rabbit/src/rabbit_autoheal.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_autoheal). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_binding.erl b/deps/rabbit/src/rabbit_binding.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_binding.erl rename to deps/rabbit/src/rabbit_binding.erl index 8782816..51bc883 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_binding.erl +++ b/deps/rabbit/src/rabbit_binding.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_binding). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_boot_steps.erl b/deps/rabbit/src/rabbit_boot_steps.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_boot_steps.erl rename to deps/rabbit/src/rabbit_boot_steps.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_channel_sup.erl b/deps/rabbit/src/rabbit_channel_sup.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_channel_sup.erl rename to deps/rabbit/src/rabbit_channel_sup.erl index b091451..48cc1e1 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_channel_sup.erl +++ b/deps/rabbit/src/rabbit_channel_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_channel_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_channel_sup_sup.erl b/deps/rabbit/src/rabbit_channel_sup_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_channel_sup_sup.erl rename to deps/rabbit/src/rabbit_channel_sup_sup.erl index 1ab74f4..885d34d 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_channel_sup_sup.erl +++ b/deps/rabbit/src/rabbit_channel_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_channel_sup_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_cli.erl b/deps/rabbit/src/rabbit_cli.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_cli.erl rename to deps/rabbit/src/rabbit_cli.erl index 4d955f8..c0e5c93 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_cli.erl +++ b/deps/rabbit/src/rabbit_cli.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_cli). @@ -154,7 +154,7 @@ start_distribution_anon(TriesLeft, _) -> start_distribution_anon(TriesLeft - 1, Reason) end. -%% Tries to start distribution with random name chosen from limited list of candidates - to +%% Tries to start distribution with random name choosen from limited list of candidates - to %% prevent atom table pollution on target nodes. start_distribution() -> rabbit_nodes:ensure_epmd(), @@ -277,7 +277,7 @@ mutually_exclusive_flags(CurrentOptionValues, Default, FlagsAndValues) -> {ok, Value}; _ -> Names = [ [$', N, $'] || {N, _} <- PresentFlags ], - CommaSeparated = string:join(rabbit_misc:lists_droplast(Names), ", "), + CommaSeparated = string:join(lists:droplast(Names), ", "), AndOneMore = lists:last(Names), Msg = io_lib:format("Options ~s and ~s are mutually exclusive", [CommaSeparated, AndOneMore]), {error, lists:flatten(Msg)} diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_client_sup.erl b/deps/rabbit/src/rabbit_client_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_client_sup.erl rename to deps/rabbit/src/rabbit_client_sup.erl index 3eaa58a..77f0bcb 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_client_sup.erl +++ b/deps/rabbit/src/rabbit_client_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_client_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_connection_helper_sup.erl b/deps/rabbit/src/rabbit_connection_helper_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_connection_helper_sup.erl rename to deps/rabbit/src/rabbit_connection_helper_sup.erl index 8b9d48d..bde520b 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_connection_helper_sup.erl +++ b/deps/rabbit/src/rabbit_connection_helper_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_connection_helper_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_connection_sup.erl b/deps/rabbit/src/rabbit_connection_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_connection_sup.erl rename to deps/rabbit/src/rabbit_connection_sup.erl index 85bd967..154bbb1 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_connection_sup.erl +++ b/deps/rabbit/src/rabbit_connection_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_connection_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_control_main.erl b/deps/rabbit/src/rabbit_control_main.erl similarity index 91% rename from rabbitmq-server/deps/rabbit/src/rabbit_control_main.erl rename to deps/rabbit/src/rabbit_control_main.erl index 50cf832..8c24589 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_control_main.erl +++ b/deps/rabbit/src/rabbit_control_main.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_control_main). @@ -31,7 +31,6 @@ -define(COMMANDS, [stop, - shutdown, stop_app, start_app, wait, @@ -71,10 +70,6 @@ {clear_parameter, [?VHOST_DEF]}, {list_parameters, [?VHOST_DEF]}, - set_global_parameter, - clear_global_parameter, - list_global_parameters, - {set_policy, [?VHOST_DEF, ?PRIORITY_DEF, ?APPLY_TO_DEF]}, {clear_policy, [?VHOST_DEF]}, {list_policies, [?VHOST_DEF]}, @@ -98,10 +93,7 @@ set_vm_memory_high_watermark, set_disk_free_limit, help, - {encode, [?DECODE_DEF, ?CIPHER_DEF, ?HASH_DEF, ?ITERATIONS_DEF, ?LIST_CIPHERS_DEF, ?LIST_HASHES_DEF]}, - {decode, [?CIPHER_DEF, ?HASH_DEF, ?ITERATIONS_DEF]}, - list_ciphers, - list_hashes + {encode, [?DECODE_DEF, ?CIPHER_DEF, ?HASH_DEF, ?ITERATIONS_DEF, ?LIST_CIPHERS_DEF, ?LIST_HASHES_DEF]} ]). -define(GLOBAL_QUERIES, @@ -120,17 +112,16 @@ {"Parameters", rabbit_runtime_parameters, list_formatted, info_keys}]). -define(COMMANDS_NOT_REQUIRING_APP, - [stop, shutdown, stop_app, start_app, wait, reset, force_reset, rotate_logs, + [stop, stop_app, start_app, wait, reset, force_reset, rotate_logs, join_cluster, change_cluster_node_type, update_cluster_nodes, forget_cluster_node, rename_cluster_node, cluster_status, status, - environment, eval, force_boot, help, hipe_compile, encode, decode, - list_ciphers, list_hashes]). + environment, eval, force_boot, help, hipe_compile, encode]). %% [Command | {Command, DefaultTimeoutInMilliSeconds}] -define(COMMANDS_WITH_TIMEOUT, [list_user_permissions, list_policies, list_queues, list_exchanges, list_bindings, list_connections, list_channels, list_consumers, - list_vhosts, list_parameters, list_global_parameters, + list_vhosts, list_parameters, purge_queue, {node_health_check, 70000}]). @@ -160,7 +151,7 @@ start() -> Inform = case Quiet of true -> fun (_Format, _Args1) -> ok end; false -> fun (Format, Args1) -> - io:format(Format ++ "~n", Args1) + io:format(Format ++ " ...~n", Args1) end end, try @@ -274,27 +265,6 @@ do_action(Command, Node, Args, Opts, Inform, Timeout) -> action(Command, Node, Args, Opts, Inform) end. -shutdown_node_and_wait_pid_to_stop(Node, Pid, Inform) -> - Inform("Shutting down RabbitMQ node ~p running at PID ~s", [Node, Pid]), - Res = call(Node, {rabbit, stop_and_halt, []}), - case Res of - ok -> - Inform("Waiting for PID ~s to terminate", [Pid]), - wait_for_process_death(Pid), - Inform( - "RabbitMQ node ~p running at PID ~s successfully shut down", - [Node, Pid]); - _ -> ok - end, - Res. - -action(shutdown, Node, [], _Opts, Inform) -> - case rpc:call(Node, os, getpid, []) of - Pid when is_list(Pid) -> - shutdown_node_and_wait_pid_to_stop(Node, Pid, Inform); - Error -> Error - end; - action(stop, Node, Args, _Opts, Inform) -> Inform("Stopping and halting node ~p", [Node]), Res = call(Node, {rabbit, stop_and_halt, []}), @@ -307,7 +277,7 @@ action(stop, Node, Args, _Opts, Inform) -> Res; action(stop_app, Node, [], _Opts, Inform) -> - Inform("Stopping rabbit application on node ~p", [Node]), + Inform("Stopping node ~p", [Node]), call(Node, {rabbit, stop, []}); action(start_app, Node, [], _Opts, Inform) -> @@ -316,14 +286,14 @@ action(start_app, Node, [], _Opts, Inform) -> action(reset, Node, [], _Opts, Inform) -> Inform("Resetting node ~p", [Node]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> call(Node, {rabbit_mnesia, reset, []}) end); action(force_reset, Node, [], _Opts, Inform) -> Inform("Forcefully resetting node ~p", [Node]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> call(Node, {rabbit_mnesia, force_reset, []}) end); @@ -335,21 +305,21 @@ action(join_cluster, Node, [ClusterNodeS], Opts, Inform) -> false -> disc end, Inform("Clustering node ~p with ~p", [Node, ClusterNode]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> rpc_call(Node, rabbit_mnesia, join_cluster, [ClusterNode, NodeType]) end); action(change_cluster_node_type, Node, ["ram"], _Opts, Inform) -> Inform("Turning ~p into a ram node", [Node]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> rpc_call(Node, rabbit_mnesia, change_cluster_node_type, [ram]) end); action(change_cluster_node_type, Node, [Type], _Opts, Inform) when Type =:= "disc" orelse Type =:= "disk" -> Inform("Turning ~p into a disc node", [Node]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> rpc_call(Node, rabbit_mnesia, change_cluster_node_type, [disc]) end); @@ -357,7 +327,7 @@ action(change_cluster_node_type, Node, [Type], _Opts, Inform) action(update_cluster_nodes, Node, [ClusterNodeS], _Opts, Inform) -> ClusterNode = list_to_atom(ClusterNodeS), Inform("Updating cluster nodes for ~p from ~p", [Node, ClusterNode]), - require_mnesia_stopped(Node, + require_mnesia_stopped(Node, fun() -> rpc_call(Node, rabbit_mnesia, update_cluster_nodes, [ClusterNode]) end); @@ -522,9 +492,9 @@ action(set_disk_free_limit, Node, ["mem_relative", Arg], _Opts, Inform) -> _ -> Arg end), Inform("Setting disk free limit on ~p to ~p of total RAM", [Node, Frac]), - rpc_call(Node, - rabbit_disk_monitor, - set_disk_free_limit, + rpc_call(Node, + rabbit_disk_monitor, + set_disk_free_limit, [{mem_relative, Frac}]); @@ -557,20 +527,6 @@ action(clear_parameter, Node, [Component, Key], Opts, Inform) -> list_to_binary(Component), list_to_binary(Key)]); -action(set_global_parameter, Node, [Key, Value], _Opts, Inform) -> - Inform("Setting global runtime parameter ~p to ~p", [Key, Value]), - rpc_call( - Node, rabbit_runtime_parameters, parse_set_global, - [rabbit_data_coercion:to_atom(Key), rabbit_data_coercion:to_binary(Value)] - ); - -action(clear_global_parameter, Node, [Key], _Opts, Inform) -> - Inform("Clearing global runtime parameter ~p", [Key]), - rpc_call( - Node, rabbit_runtime_parameters, clear_global, - [rabbit_data_coercion:to_atom(Key)] - ); - action(set_policy, Node, [Key, Pattern, Defn], Opts, Inform) -> Msg = "Setting policy ~p for pattern ~p to ~p with priority ~p", VHostArg = list_to_binary(proplists:get_value(?VHOST_OPT, Opts)), @@ -624,38 +580,15 @@ action(eval, Node, [Expr], _Opts, _Inform) -> action(help, _Node, _Args, _Opts, _Inform) -> io:format("~s", [rabbit_ctl_usage:usage()]); -action(encode, Node, Args, Opts, Inform) -> +action(encode, _Node, Args, Opts, _Inform) -> ListCiphers = lists:member({?LIST_CIPHERS_OPT, true}, Opts), ListHashes = lists:member({?LIST_HASHES_OPT, true}, Opts), Decode = lists:member({?DECODE_OPT, true}, Opts), - case {ListCiphers, ListHashes, Decode} of - {true, _, _} -> - action(list_ciphers, Node, Args, Opts, Inform); - {_, true, _} -> - action(list_hashes, Node, Args, Opts, Inform); - {_, _, true} -> - action(decode, Node, Args, Opts, Inform); - {_, _, _} -> - Cipher = list_to_atom(proplists:get_value(?CIPHER_OPT, Opts)), - Hash = list_to_atom(proplists:get_value(?HASH_OPT, Opts)), - Iterations = list_to_integer(proplists:get_value(?ITERATIONS_OPT, Opts)), - {_, Msg} = rabbit_control_pbe:encode(Cipher, Hash, Iterations, Args), - io:format(Msg ++ "~n") - end; - -action(decode, _Node, Args, Opts, _Inform) -> Cipher = list_to_atom(proplists:get_value(?CIPHER_OPT, Opts)), Hash = list_to_atom(proplists:get_value(?HASH_OPT, Opts)), Iterations = list_to_integer(proplists:get_value(?ITERATIONS_OPT, Opts)), - {_, Msg} = rabbit_control_pbe:decode(Cipher, Hash, Iterations, Args), - io:format(Msg ++ "~n"); - -action(list_hashes, _Node, _Args, _Opts, _Inform) -> - {_, Msg} = rabbit_control_pbe:list_hashes(), - io:format(Msg ++ "~n"); -action(list_ciphers, _Node, _Args, _Opts, _Inform) -> - {_, Msg} = rabbit_control_pbe:list_ciphers(), + {_, Msg} = rabbit_control_pbe:encode(ListCiphers, ListHashes, Decode, Cipher, Hash, Iterations, Args), io:format(Msg ++ "~n"); action(Command, Node, Args, Opts, Inform) -> @@ -690,11 +623,6 @@ action(list_parameters, Node, [], Opts, Inform, Timeout) -> call(Node, {rabbit_runtime_parameters, list_formatted, [VHostArg]}, rabbit_runtime_parameters:info_keys(), Timeout); -action(list_global_parameters, Node, [], _Opts, Inform, Timeout) -> - Inform("Listing global runtime parameters", []), - call(Node, {rabbit_runtime_parameters, list_global_formatted, []}, - rabbit_runtime_parameters:global_info_keys(), Timeout); - action(list_policies, Node, [], Opts, Inform, Timeout) -> VHostArg = list_to_binary(proplists:get_value(?VHOST_OPT, Opts)), Inform("Listing policies", []), @@ -1011,7 +939,7 @@ escape(Bin, IsEscaped) when is_binary(Bin) -> escape(L, false) when is_list(L) -> escape_char(lists:reverse(L), []); escape(L, true) when is_list(L) -> - L. + L. escape_char([$\\ | T], Acc) -> escape_char(T, [$\\, $\\ | Acc]); diff --git a/deps/rabbit/src/rabbit_control_pbe.erl b/deps/rabbit/src/rabbit_control_pbe.erl new file mode 100644 index 0000000..2fa2c90 --- /dev/null +++ b/deps/rabbit/src/rabbit_control_pbe.erl @@ -0,0 +1,79 @@ +% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_control_pbe). + +-export([encode/7]). + +% for testing purposes +-export([evaluate_input_as_term/1]). + +encode(ListCiphers, _ListHashes, _Decode, _Cipher, _Hash, _Iterations, _Args) when ListCiphers -> + {ok, io_lib:format("~p", [rabbit_pbe:supported_ciphers()])}; + +encode(_ListCiphers, ListHashes, _Decode, _Cipher, _Hash, _Iterations, _Args) when ListHashes -> + {ok, io_lib:format("~p", [rabbit_pbe:supported_hashes()])}; + +encode(_ListCiphers, _ListHashes, Decode, Cipher, Hash, Iterations, Args) -> + CipherExists = lists:member(Cipher, rabbit_pbe:supported_ciphers()), + HashExists = lists:member(Hash, rabbit_pbe:supported_hashes()), + encode_encrypt_decrypt(CipherExists, HashExists, Decode, Cipher, Hash, Iterations, Args). + +encode_encrypt_decrypt(CipherExists, _HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) when CipherExists =:= false -> + {error, io_lib:format("The requested cipher is not supported", [])}; + +encode_encrypt_decrypt(_CipherExists, HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) when HashExists =:= false -> + {error, io_lib:format("The requested hash is not supported", [])}; + +encode_encrypt_decrypt(_CipherExists, _HashExists, _Decode, _Cipher, _Hash, Iterations, _Args) when Iterations =< 0 -> + {error, io_lib:format("The requested number of iterations is incorrect", [])}; + +encode_encrypt_decrypt(_CipherExists, _HashExists, Decode, Cipher, Hash, Iterations, Args) when length(Args) == 2, Decode =:= false -> + [Value, PassPhrase] = Args, + try begin + TermValue = evaluate_input_as_term(Value), + Result = rabbit_pbe:encrypt_term(Cipher, Hash, Iterations, list_to_binary(PassPhrase), TermValue), + {ok, io_lib:format("~p", [{encrypted, Result}])} + end + catch + _:Msg -> {error, io_lib:format("Error during cipher operation: ~p", [Msg])} + end; + +encode_encrypt_decrypt(_CipherExists, _HashExists, Decode, Cipher, Hash, Iterations, Args) when length(Args) == 2, Decode -> + [Value, PassPhrase] = Args, + try begin + TermValue = evaluate_input_as_term(Value), + TermToDecrypt = case TermValue of + {encrypted, EncryptedTerm} -> + EncryptedTerm; + _ -> + TermValue + end, + Result = rabbit_pbe:decrypt_term(Cipher, Hash, Iterations, list_to_binary(PassPhrase), TermToDecrypt), + {ok, io_lib:format("~p", [Result])} + end + catch + _:Msg -> {error, io_lib:format("Error during cipher operation: ~p", [Msg])} + end; + +encode_encrypt_decrypt(_CipherExists, _HashExists, _Decode, _Cipher, _Hash, _Iterations, _Args) -> + {error, io_lib:format("Please provide a value to encode/decode and a passphrase", [])}. + +evaluate_input_as_term(Input) -> + {ok,Tokens,_EndLine} = erl_scan:string(Input ++ "."), + {ok,AbsForm} = erl_parse:parse_exprs(Tokens), + {value,TermValue,_Bs} = erl_eval:exprs(AbsForm, erl_eval:new_bindings()), + TermValue. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_dead_letter.erl b/deps/rabbit/src/rabbit_dead_letter.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_dead_letter.erl rename to deps/rabbit/src/rabbit_dead_letter.erl index af897cc..91d23c8 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_dead_letter.erl +++ b/deps/rabbit/src/rabbit_dead_letter.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_dead_letter). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_diagnostics.erl b/deps/rabbit/src/rabbit_diagnostics.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_diagnostics.erl rename to deps/rabbit/src/rabbit_diagnostics.erl index 19082c0..d28bb9f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_diagnostics.erl +++ b/deps/rabbit/src/rabbit_diagnostics.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_diagnostics). @@ -64,6 +64,7 @@ maybe_stuck_stacktrace({prim_inet, accept0, _}) -> false; maybe_stuck_stacktrace({prim_inet, recv0, _}) -> false; maybe_stuck_stacktrace({rabbit_heartbeat, heartbeater, _}) -> false; maybe_stuck_stacktrace({rabbit_net, recv, _}) -> false; +maybe_stuck_stacktrace({mochiweb_http, request, _}) -> false; maybe_stuck_stacktrace({group, _, _}) -> false; maybe_stuck_stacktrace({shell, _, _}) -> false; maybe_stuck_stacktrace({io, _, _}) -> false; diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_direct.erl b/deps/rabbit/src/rabbit_direct.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_direct.erl rename to deps/rabbit/src/rabbit_direct.erl index 3c3da5e..061105c 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_direct.erl +++ b/deps/rabbit/src/rabbit_direct.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_direct). @@ -109,7 +109,6 @@ authz_socket_info_direct(Infos) -> connect1(User, VHost, Protocol, Pid, Infos) -> try rabbit_access_control:check_vhost_access(User, VHost, authz_socket_info_direct(Infos)) of ok -> ok = pg_local:join(rabbit_direct, Pid), - rabbit_core_metrics:connection_created(Pid, Infos), rabbit_event:notify(connection_created, Infos), {ok, {User, rabbit_reader:server_properties(Protocol)}} catch @@ -128,5 +127,4 @@ start_channel(Number, ClientChannelPid, ConnPid, ConnName, Protocol, User, disconnect(Pid, Infos) -> pg_local:leave(rabbit_direct, Pid), - rabbit_core_metrics:connection_closed(Pid), rabbit_event:notify(connection_closed, Infos). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_disk_monitor.erl b/deps/rabbit/src/rabbit_disk_monitor.erl similarity index 86% rename from rabbitmq-server/deps/rabbit/src/rabbit_disk_monitor.erl rename to deps/rabbit/src/rabbit_disk_monitor.erl index 868fc1a..4c1ff02 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_disk_monitor.erl +++ b/deps/rabbit/src/rabbit_disk_monitor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_disk_monitor). @@ -65,17 +65,12 @@ alarmed, %% is monitoring enabled? false on unsupported %% platforms - enabled, - %% number of retries to enable monitoring if it fails - %% on start-up - retries, - %% Interval between retries - interval + enabled }). %%---------------------------------------------------------------------------- --type disk_free_limit() :: (integer() | string() | {'mem_relative', float() | integer()}). +-type disk_free_limit() :: (integer() | string() | {'mem_relative', float()}). -spec start_link(disk_free_limit()) -> rabbit_types:ok_pid_or_error(). -spec get_disk_free_limit() -> integer(). -spec set_disk_free_limit(disk_free_limit()) -> 'ok'. @@ -119,17 +114,20 @@ start_link(Args) -> init([Limit]) -> Dir = dir(), - {ok, Retries} = application:get_env(rabbit, disk_monitor_failure_retries), - {ok, Interval} = application:get_env(rabbit, disk_monitor_failure_retry_interval), State = #state{dir = Dir, min_interval = ?DEFAULT_MIN_DISK_CHECK_INTERVAL, max_interval = ?DEFAULT_MAX_DISK_CHECK_INTERVAL, alarmed = false, - enabled = true, - limit = Limit, - retries = Retries, - interval = Interval}, - {ok, enable(State)}. + enabled = true}, + case {catch get_disk_free(Dir), + vm_memory_monitor:get_total_memory()} of + {N1, N2} when is_integer(N1), is_integer(N2) -> + {ok, start_timer(set_disk_limits(State, Limit))}; + Err -> + rabbit_log:info("Disabling disk free space monitoring " + "on unsupported platform:~n~p~n", [Err]), + {ok, State#state{enabled = false}} + end. handle_call(get_disk_free_limit, _From, State = #state{limit = Limit}) -> {reply, Limit, State}; @@ -163,8 +161,6 @@ handle_call(_Request, _From, State) -> handle_cast(_Request, State) -> {noreply, State}. -handle_info(try_enable, #state{retries = Retries} = State) -> - {noreply, enable(State#state{retries = Retries - 1})}; handle_info(update, State) -> {noreply, start_timer(internal_update(State))}; @@ -237,7 +233,7 @@ parse_free_win32(CommandResult) -> list_to_integer(lists:reverse(Free)). interpret_limit({mem_relative, Relative}) - when is_number(Relative) -> + when is_float(Relative) -> round(Relative * vm_memory_monitor:get_total_memory()); interpret_limit(Absolute) -> case rabbit_resource_monitor_misc:parse_information_unit(Absolute) of @@ -250,7 +246,7 @@ interpret_limit(Absolute) -> emit_update_info(StateStr, CurrentFree, Limit) -> rabbit_log:info( - "Free disk space is ~s. Free bytes: ~p. Limit: ~p~n", + "Disk free space ~s. Free bytes:~p Limit:~p~n", [StateStr, CurrentFree, Limit]). start_timer(State) -> @@ -265,20 +261,3 @@ interval(#state{limit = Limit, max_interval = MaxInterval}) -> IdealInterval = 2 * (Actual - Limit) / ?FAST_RATE, trunc(erlang:max(MinInterval, erlang:min(MaxInterval, IdealInterval))). - -enable(#state{retries = 0} = State) -> - State; -enable(#state{dir = Dir, interval = Interval, limit = Limit, retries = Retries} - = State) -> - case {catch get_disk_free(Dir), - vm_memory_monitor:get_total_memory()} of - {N1, N2} when is_integer(N1), is_integer(N2) -> - rabbit_log:info("Enabling free disk space monitoring~n", []), - start_timer(set_disk_limits(State, Limit)); - Err -> - rabbit_log:info("Free disk space monitor encountered an error " - "(e.g. failed to parse output from OS tools): ~p, retries left: ~s~n", - [Err, Retries]), - timer:send_after(Interval, self(), try_enable), - State#state{enabled = false} - end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_epmd_monitor.erl b/deps/rabbit/src/rabbit_epmd_monitor.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_epmd_monitor.erl rename to deps/rabbit/src/rabbit_epmd_monitor.erl index 9d8044e..7f01a71 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_epmd_monitor.erl +++ b/deps/rabbit/src/rabbit_epmd_monitor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_epmd_monitor). @@ -92,6 +92,6 @@ check_epmd(#state{mod = Mod, "epmd does not know us, re-registering ~s at port ~b~n", [Me, Port]), rabbit_nodes:ensure_epmd(), - Mod:register_node(Me, Port); + erl_epmd:register_node(Me, Port); _ -> ok end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_error_logger.erl b/deps/rabbit/src/rabbit_error_logger.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_error_logger.erl rename to deps/rabbit/src/rabbit_error_logger.erl index 4f7c4e3..5ba3ce7 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_error_logger.erl +++ b/deps/rabbit/src/rabbit_error_logger.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_error_logger). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_error_logger_file_h.erl b/deps/rabbit/src/rabbit_error_logger_file_h.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_error_logger_file_h.erl rename to deps/rabbit/src/rabbit_error_logger_file_h.erl index 49a95ad..930aead 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_error_logger_file_h.erl +++ b/deps/rabbit/src/rabbit_error_logger_file_h.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_error_logger_file_h). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange.erl b/deps/rabbit/src/rabbit_exchange.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange.erl rename to deps/rabbit/src/rabbit_exchange.erl index 253b507..aaea27f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange.erl +++ b/deps/rabbit/src/rabbit_exchange.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange). @@ -23,7 +23,7 @@ lookup/1, lookup_or_die/1, list/0, list/1, lookup_scratch/2, update_scratch/3, update_decorators/1, immutable/1, info_keys/0, info/1, info/2, info_all/1, info_all/2, info_all/4, - route/2, delete/2, validate_binding/2, list_names/0]). + route/2, delete/2, validate_binding/2]). %% these must be run inside a mnesia tx -export([maybe_auto_delete/2, serial/1, peek_serial/1, update/2]). @@ -61,7 +61,6 @@ (name()) -> rabbit_types:exchange() | rabbit_types:channel_exit(). -spec list() -> [rabbit_types:exchange()]. --spec list_names() -> [rabbit_exchange:name()]. -spec list(rabbit_types:vhost()) -> [rabbit_types:exchange()]. -spec lookup_scratch(name(), atom()) -> rabbit_types:ok(term()) | @@ -259,8 +258,6 @@ lookup_or_die(Name) -> list() -> mnesia:dirty_match_object(rabbit_exchange, #exchange{_ = '_'}). -list_names() -> mnesia:dirty_all_keys(rabbit_exchange). - %% Not dirty_match_object since that would not be transactional when used in a %% tx context list(VHostPath) -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_parameters.erl b/deps/rabbit/src/rabbit_exchange_parameters.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_parameters.erl rename to deps/rabbit/src/rabbit_exchange_parameters.erl index 3e80cb5..c0ca0a9 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_parameters.erl +++ b/deps/rabbit/src/rabbit_exchange_parameters.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_parameters). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_direct.erl b/deps/rabbit/src/rabbit_exchange_type_direct.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_direct.erl rename to deps/rabbit/src/rabbit_exchange_type_direct.erl index 3544a82..8a6886e 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_direct.erl +++ b/deps/rabbit/src/rabbit_exchange_type_direct.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_direct). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_fanout.erl b/deps/rabbit/src/rabbit_exchange_type_fanout.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_fanout.erl rename to deps/rabbit/src/rabbit_exchange_type_fanout.erl index 04dc2b8..d81e407 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_fanout.erl +++ b/deps/rabbit/src/rabbit_exchange_type_fanout.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_fanout). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_headers.erl b/deps/rabbit/src/rabbit_exchange_type_headers.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_headers.erl rename to deps/rabbit/src/rabbit_exchange_type_headers.erl index 4702fba..196873a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_headers.erl +++ b/deps/rabbit/src/rabbit_exchange_type_headers.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_headers). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_invalid.erl b/deps/rabbit/src/rabbit_exchange_type_invalid.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_invalid.erl rename to deps/rabbit/src/rabbit_exchange_type_invalid.erl index 81318cb..2510c8a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_invalid.erl +++ b/deps/rabbit/src/rabbit_exchange_type_invalid.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_invalid). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_topic.erl b/deps/rabbit/src/rabbit_exchange_type_topic.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_topic.erl rename to deps/rabbit/src/rabbit_exchange_type_topic.erl index f04f68f..0eccb66 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_type_topic.erl +++ b/deps/rabbit/src/rabbit_exchange_type_topic.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_topic). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_file.erl b/deps/rabbit/src/rabbit_file.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_file.erl rename to deps/rabbit/src/rabbit_file.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_framing.erl b/deps/rabbit/src/rabbit_framing.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_framing.erl rename to deps/rabbit/src/rabbit_framing.erl index 5ed83ae..e4a5013 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_framing.erl +++ b/deps/rabbit/src/rabbit_framing.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% TODO auto-generate diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_guid.erl b/deps/rabbit/src/rabbit_guid.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_guid.erl rename to deps/rabbit/src/rabbit_guid.erl index bd2e7e1..75f9df7 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_guid.erl +++ b/deps/rabbit/src/rabbit_guid.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_guid). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_hipe.erl b/deps/rabbit/src/rabbit_hipe.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_hipe.erl rename to deps/rabbit/src/rabbit_hipe.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_limiter.erl b/deps/rabbit/src/rabbit_limiter.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_limiter.erl rename to deps/rabbit/src/rabbit_limiter.erl index 1e715a8..203e309 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_limiter.erl +++ b/deps/rabbit/src/rabbit_limiter.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% The purpose of the limiter is to stem the flow of messages from diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_log.erl b/deps/rabbit/src/rabbit_log.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_log.erl rename to deps/rabbit/src/rabbit_log.erl index df34bec..337fb23 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_log.erl +++ b/deps/rabbit/src/rabbit_log.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_log). @@ -27,12 +27,24 @@ -type category() :: atom(). -type level() :: 'debug' | 'info' | 'warning' | 'error'. +-spec log(category(), level(), string()) -> 'ok'. +-spec log(category(), level(), string(), [any()]) -> 'ok'. + +-spec debug(string()) -> 'ok'. +-spec debug(string(), [any()]) -> 'ok'. +-spec info(string()) -> 'ok'. +-spec info(string(), [any()]) -> 'ok'. +-spec warning(string()) -> 'ok'. +-spec warning(string(), [any()]) -> 'ok'. +-spec error(string()) -> 'ok'. +-spec error(string(), [any()]) -> 'ok'. + +-spec with_local_io(fun (() -> A)) -> A. + %%---------------------------------------------------------------------------- --spec log(category(), level(), string()) -> 'ok'. log(Category, Level, Fmt) -> log(Category, Level, Fmt, []). --spec log(category(), level(), string(), [any()]) -> 'ok'. log(Category, Level, Fmt, Args) when is_list(Args) -> case level(Level) =< catlevel(Category) of false -> ok; @@ -45,21 +57,13 @@ log(Category, Level, Fmt, Args) when is_list(Args) -> with_local_io(fun () -> F(Fmt, Args) end) end. --spec debug(string()) -> 'ok'. debug(Fmt) -> log(default, debug, Fmt). --spec debug(string(), [any()]) -> 'ok'. debug(Fmt, Args) -> log(default, debug, Fmt, Args). --spec info(string()) -> 'ok'. info(Fmt) -> log(default, info, Fmt). --spec info(string(), [any()]) -> 'ok'. info(Fmt, Args) -> log(default, info, Fmt, Args). --spec warning(string()) -> 'ok'. warning(Fmt) -> log(default, warning, Fmt). --spec warning(string(), [any()]) -> 'ok'. warning(Fmt, Args) -> log(default, warning, Fmt, Args). --spec error(string()) -> 'ok'. error(Fmt) -> log(default, error, Fmt). --spec error(string(), [any()]) -> 'ok'. error(Fmt, Args) -> log(default, error, Fmt, Args). catlevel(Category) -> @@ -83,7 +87,6 @@ level(none) -> 0. %% Execute Fun using the IO system of the local node (i.e. the node on %% which the code is executing). Since this is invoked for every log %% message, we try to avoid unnecessarily churning group_leader/1. --spec with_local_io(fun (() -> A)) -> A. with_local_io(Fun) -> GL = group_leader(), Node = node(), diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_memory_monitor.erl b/deps/rabbit/src/rabbit_memory_monitor.erl similarity index 95% rename from rabbitmq-server/deps/rabbit/src/rabbit_memory_monitor.erl rename to deps/rabbit/src/rabbit_memory_monitor.erl index 06ffb77..6fd12b3 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_memory_monitor.erl +++ b/deps/rabbit/src/rabbit_memory_monitor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% @@ -89,8 +89,18 @@ conserve_resources(Pid, disk, {_, Conserve, Node}) when node(Pid) =:= Node -> conserve_resources(_Pid, _Source, _Conserve) -> ok. -memory_use(Type) -> - vm_memory_monitor:get_memory_use(Type). +memory_use(bytes) -> + MemoryLimit = vm_memory_monitor:get_memory_limit(), + {erlang:memory(total), case MemoryLimit > 0.0 of + true -> MemoryLimit; + false -> infinity + end}; +memory_use(ratio) -> + MemoryLimit = vm_memory_monitor:get_memory_limit(), + case MemoryLimit > 0.0 of + true -> erlang:memory(total) / MemoryLimit; + false -> infinity + end. %%---------------------------------------------------------------------------- %% Gen_server callbacks diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_coordinator.erl b/deps/rabbit/src/rabbit_mirror_queue_coordinator.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_coordinator.erl rename to deps/rabbit/src/rabbit_mirror_queue_coordinator.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_master.erl b/deps/rabbit/src/rabbit_mirror_queue_master.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_master.erl rename to deps/rabbit/src/rabbit_mirror_queue_master.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_misc.erl b/deps/rabbit/src/rabbit_mirror_queue_misc.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_misc.erl rename to deps/rabbit/src/rabbit_mirror_queue_misc.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode.erl b/deps/rabbit/src/rabbit_mirror_queue_mode.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode.erl rename to deps/rabbit/src/rabbit_mirror_queue_mode.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_all.erl b/deps/rabbit/src/rabbit_mirror_queue_mode_all.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_all.erl rename to deps/rabbit/src/rabbit_mirror_queue_mode_all.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_exactly.erl b/deps/rabbit/src/rabbit_mirror_queue_mode_exactly.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_exactly.erl rename to deps/rabbit/src/rabbit_mirror_queue_mode_exactly.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_nodes.erl b/deps/rabbit/src/rabbit_mirror_queue_mode_nodes.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_mode_nodes.erl rename to deps/rabbit/src/rabbit_mirror_queue_mode_nodes.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_slave.erl b/deps/rabbit/src/rabbit_mirror_queue_slave.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_slave.erl rename to deps/rabbit/src/rabbit_mirror_queue_slave.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_sync.erl b/deps/rabbit/src/rabbit_mirror_queue_sync.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_sync.erl rename to deps/rabbit/src/rabbit_mirror_queue_sync.erl index 9e61824..c438e91 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_mirror_queue_sync.erl +++ b/deps/rabbit/src/rabbit_mirror_queue_sync.erl @@ -16,7 +16,7 @@ -module(rabbit_mirror_queue_sync). --include_lib("rabbit_common/include/rabbit.hrl"). +-include("rabbit.hrl"). -export([master_prepare/4, master_go/8, slave/7, conserve_resources/3]). @@ -37,7 +37,7 @@ %% %% Master Syncer Slave(s) %% sync_mirrors -> || || -%% || -- (spawns) --> || || +%% (from channel) || -- (spawns) --> || || %% || --------- sync_start (over GM) -------> || %% || || <--- sync_ready ---- || %% || || (or) || diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mnesia.erl b/deps/rabbit/src/rabbit_mnesia.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_mnesia.erl rename to deps/rabbit/src/rabbit_mnesia.erl index 449b5ba..596eb62 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_mnesia.erl +++ b/deps/rabbit/src/rabbit_mnesia.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mnesia). @@ -104,7 +104,7 @@ init() -> false -> NodeType = node_type(), init_db_and_upgrade(cluster_nodes(all), NodeType, - NodeType =:= ram, _Retry = true) + NodeType =:= ram) end, %% We intuitively expect the global name server to be synced when %% Mnesia is up. In fact that's not guaranteed to be the case - @@ -138,7 +138,7 @@ init_from_config() -> e(invalid_cluster_nodes_conf) end, case TryNodes of - [] -> init_db_and_upgrade([node()], disc, false, _Retry = true); + [] -> init_db_and_upgrade([node()], disc, false); _ -> auto_cluster(TryNodes, NodeType) end. @@ -147,13 +147,13 @@ auto_cluster(TryNodes, NodeType) -> {ok, Node} -> rabbit_log:info("Node '~p' selected for auto-clustering~n", [Node]), {ok, {_, DiscNodes, _}} = discover_cluster0(Node), - init_db_and_upgrade(DiscNodes, NodeType, true, _Retry = true), + init_db_and_upgrade(DiscNodes, NodeType, true), rabbit_node_monitor:notify_joined_cluster(); none -> rabbit_log:warning( "Could not find any node for auto-clustering from: ~p~n" "Starting blank node...~n", [TryNodes]), - init_db_and_upgrade([node()], disc, false, _Retry = true) + init_db_and_upgrade([node()], disc, false) end. %% Make the node join a cluster. The node will be reset automatically @@ -193,7 +193,7 @@ join_cluster(DiscoveryNode, NodeType) -> rabbit_log:info("Clustering with ~p as ~p node~n", [ClusterNodes, NodeType]), ok = init_db_with_mnesia(ClusterNodes, NodeType, - true, true, _Retry = true), + true, true), rabbit_node_monitor:notify_joined_cluster(), ok; {error, Reason} -> @@ -232,7 +232,7 @@ reset_gracefully() -> %% need to check for consistency because we are resetting. %% Force=true here so that reset still works when clustered with a %% node which is down. - init_db_with_mnesia(AllNodes, node_type(), false, false, _Retry = false), + init_db_with_mnesia(AllNodes, node_type(), false, false), case is_only_clustered_disc_node() of true -> e(resetting_only_disc_node); false -> ok @@ -281,7 +281,7 @@ update_cluster_nodes(DiscoveryNode) -> rabbit_node_monitor:write_cluster_status(Status), rabbit_log:info("Updating cluster nodes from ~p~n", [DiscoveryNode]), - init_db_with_mnesia(AllNodes, node_type(), true, true, _Retry = false); + init_db_with_mnesia(AllNodes, node_type(), true, true); false -> e(inconsistent_cluster) end, @@ -325,7 +325,7 @@ remove_node_offline_node(Node) -> %% is by force loading the table, and making sure that %% they are loaded. rabbit_table:force_load(), - rabbit_table:wait_for_replicated(_Retry = false), + rabbit_table:wait_for_replicated(), forget_cluster_node(Node, false), force_load_next_boot() after @@ -470,7 +470,7 @@ init_db(ClusterNodes, NodeType, CheckOtherNodes) -> {[_ | _], _, _} -> %% Subsequent node in cluster, catch up maybe_force_load(), - ok = rabbit_table:wait_for_replicated(_Retry = true), + ok = rabbit_table:wait_for_replicated(), ok = rabbit_table:create_local_copy(NodeType) end, ensure_schema_integrity(), @@ -480,7 +480,7 @@ init_db(ClusterNodes, NodeType, CheckOtherNodes) -> init_db_unchecked(ClusterNodes, NodeType) -> init_db(ClusterNodes, NodeType, false). -init_db_and_upgrade(ClusterNodes, NodeType, CheckOtherNodes, Retry) -> +init_db_and_upgrade(ClusterNodes, NodeType, CheckOtherNodes) -> ok = init_db(ClusterNodes, NodeType, CheckOtherNodes), ok = case rabbit_upgrade:maybe_upgrade_local() of ok -> ok; @@ -495,14 +495,14 @@ init_db_and_upgrade(ClusterNodes, NodeType, CheckOtherNodes, Retry) -> disc -> ok end, %% ...and all nodes will need to wait for tables - rabbit_table:wait_for_replicated(Retry), + rabbit_table:wait_for_replicated(), ok. init_db_with_mnesia(ClusterNodes, NodeType, - CheckOtherNodes, CheckConsistency, Retry) -> + CheckOtherNodes, CheckConsistency) -> start_mnesia(CheckConsistency), try - init_db_and_upgrade(ClusterNodes, NodeType, CheckOtherNodes, Retry) + init_db_and_upgrade(ClusterNodes, NodeType, CheckOtherNodes) after stop_mnesia() end. @@ -539,7 +539,7 @@ ensure_mnesia_not_running() -> end. ensure_schema_integrity() -> - case rabbit_table:check_schema_integrity(_Retry = true) of + case rabbit_table:check_schema_integrity() of ok -> ok; {error, Reason} -> @@ -670,7 +670,7 @@ discover_cluster0(Node) -> rpc:call(Node, rabbit_mnesia, cluster_status_from_mnesia, []). schema_ok_or_move() -> - case rabbit_table:check_schema_integrity(_Retry = false) of + case rabbit_table:check_schema_integrity() of ok -> ok; {error, Reason} -> @@ -840,12 +840,12 @@ with_running_or_clean_mnesia(Fun) -> case IsMnesiaRunning of true -> Fun(); false -> - SavedMnesiaDir = dir(), + {ok, MnesiaDir} = application:get_env(mnesia, dir), application:unset_env(mnesia, dir), mnesia:start(), Result = Fun(), application:stop(mnesia), - application:set_env(mnesia, dir, SavedMnesiaDir), + application:set_env(mnesia, dir, MnesiaDir), Result end. @@ -858,7 +858,7 @@ check_rabbit_consistency(Remote) -> %% that a `reset' would leave it in. We cannot simply check if the %% mnesia tables aren't there because restarted RAM nodes won't have %% tables while still being non-virgin. What we do instead is to -%% check if the mnesia directory is non existent or empty, with the +%% check if the mnesia directory is non existant or empty, with the %% exception of the cluster status files, which will be there thanks to %% `rabbit_node_monitor:prepare_cluster_status_file/0'. is_virgin_node() -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_mnesia_rename.erl b/deps/rabbit/src/rabbit_mnesia_rename.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_mnesia_rename.erl rename to deps/rabbit/src/rabbit_mnesia_rename.erl index a28ddc8..0945e31 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_mnesia_rename.erl +++ b/deps/rabbit/src/rabbit_mnesia_rename.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mnesia_rename). @@ -187,7 +187,7 @@ delete_rename_files() -> ok = rabbit_file:recursive_delete([dir()]). start_mnesia() -> rabbit_misc:ensure_ok(mnesia:start(), cannot_start_mnesia), rabbit_table:force_load(), - rabbit_table:wait_for_replicated(_Retry = false). + rabbit_table:wait_for_replicated(). stop_mnesia() -> stopped = mnesia:stop(). convert_backup(NodeMap, FromBackup, ToBackup) -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_msg_file.erl b/deps/rabbit/src/rabbit_msg_file.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_msg_file.erl rename to deps/rabbit/src/rabbit_msg_file.erl index eb23d3a..5c0acc5 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_msg_file.erl +++ b/deps/rabbit/src/rabbit_msg_file.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_msg_file). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store.erl b/deps/rabbit/src/rabbit_msg_store.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_msg_store.erl rename to deps/rabbit/src/rabbit_msg_store.erl index ec828fe..d3ff077 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store.erl +++ b/deps/rabbit/src/rabbit_msg_store.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_msg_store). @@ -265,7 +265,7 @@ %% updated. %% %% On non-clean startup, we scan the files we discover, dealing with -%% the possibilites of a crash having occurred during a compaction +%% the possibilites of a crash having occured during a compaction %% (this consists of tidyup - the compaction is deliberately designed %% such that data is duplicated on disk rather than risking it being %% lost), and rebuild the file summary and index ETS table. @@ -310,7 +310,7 @@ %% From this reasoning, we do have a bound on the number of times the %% message is rewritten. From when it is inserted, there can be no %% files inserted between it and the head of the queue, and the worst -%% case is that every time it is rewritten, it moves one position lower +%% case is that everytime it is rewritten, it moves one position lower %% in the file (for it to stay at the same position requires that %% there are no holes beneath it, which means truncate would be used %% and so it would not be rewritten at all). Thus this seems to @@ -352,7 +352,7 @@ %% because in the event of the same message being sent to several %% different queues, there is the possibility of one queue writing and %% removing the message before other queues write it at all. Thus -%% accommodating 0-reference counts allows us to avoid unnecessary +%% accomodating 0-reference counts allows us to avoid unnecessary %% writes here. Of course, there are complications: the file to which %% the message has already been written could be locked pending %% deletion or GC, which means we have to rewrite the message as the @@ -985,7 +985,6 @@ terminate(_Reason, State = #msstate { index_state = IndexState, flying_ets = FlyingEts, clients = Clients, dir = Dir }) -> - rabbit_log:info("Stopping message store for directory '~s'", [Dir]), %% stop the gc first, otherwise it could be working and we pull %% out the ets tables from under it. ok = rabbit_msg_store_gc:stop(GCPid), @@ -1002,7 +1001,6 @@ terminate(_Reason, State = #msstate { index_state = IndexState, IndexModule:terminate(IndexState), ok = store_recovery_terms([{client_refs, dict:fetch_keys(Clients)}, {index_module, IndexModule}], Dir), - rabbit_log:info("Message store for directory '~s' is stopped", [Dir]), State3 #msstate { index_state = undefined, current_file_handle = undefined }. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store_ets_index.erl b/deps/rabbit/src/rabbit_msg_store_ets_index.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_msg_store_ets_index.erl rename to deps/rabbit/src/rabbit_msg_store_ets_index.erl index 967b037..76ef112 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store_ets_index.erl +++ b/deps/rabbit/src/rabbit_msg_store_ets_index.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_msg_store_ets_index). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store_gc.erl b/deps/rabbit/src/rabbit_msg_store_gc.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_msg_store_gc.erl rename to deps/rabbit/src/rabbit_msg_store_gc.erl index 6179ef9..9cfdba8 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_msg_store_gc.erl +++ b/deps/rabbit/src/rabbit_msg_store_gc.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_msg_store_gc). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_node_monitor.erl b/deps/rabbit/src/rabbit_node_monitor.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_node_monitor.erl rename to deps/rabbit/src/rabbit_node_monitor.erl index 810df2d..bea2a3f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_node_monitor.erl +++ b/deps/rabbit/src/rabbit_node_monitor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_node_monitor). @@ -344,8 +344,8 @@ init([]) -> Nodes = possibly_partitioned_nodes(), startup_log(Nodes), Monitors = lists:foldl(fun(Node, Monitors0) -> - pmon:monitor({rabbit, Node}, Monitors0) - end, pmon:new(), Nodes), + pmon:monitor({rabbit, Node}, Monitors0) + end, pmon:new(), Nodes), {ok, ensure_keepalive_timer(#state{monitors = Monitors, subscribers = pmon:new(), partitions = [], @@ -420,12 +420,12 @@ handle_cast({check_partial_partition, Node, Rep, NodeGUID, MyGUID, RepGUID}, fun () -> case rpc:call(Node, rabbit, is_running, []) of {badrpc, _} -> ok; - _ -> - rabbit_log:warning("Received a 'DOWN' message" - " from ~p but still can" - " communicate with it ~n", - [Node]), - cast(Rep, {partial_partition, + _ -> + rabbit_log:warning("Received a 'DOWN' message" + " from ~p but still can" + " communicate with it ~n", + [Node]), + cast(Rep, {partial_partition, Node, node(), RepGUID}) end end); @@ -499,18 +499,18 @@ handle_cast({node_up, Node, NodeType}, rabbit_log:info("rabbit on node ~p up~n", [Node]), {AllNodes, DiscNodes, RunningNodes} = read_cluster_status(), write_cluster_status({add_node(Node, AllNodes), - case NodeType of - disc -> add_node(Node, DiscNodes); - ram -> DiscNodes - end, - add_node(Node, RunningNodes)}), + case NodeType of + disc -> add_node(Node, DiscNodes); + ram -> DiscNodes + end, + add_node(Node, RunningNodes)}), ok = handle_live_rabbit(Node), Monitors1 = case pmon:is_monitored({rabbit, Node}, Monitors) of - true -> - Monitors; - false -> - pmon:monitor({rabbit, Node}, Monitors) - end, + true -> + Monitors; + false -> + pmon:monitor({rabbit, Node}, Monitors) + end, {noreply, maybe_autoheal(State#state{monitors = Monitors1})}; handle_cast({joined_cluster, Node, NodeType}, State) -> @@ -584,7 +584,7 @@ handle_info({mnesia_system_event, State1 = case pmon:is_monitored({rabbit, Node}, Monitors) of true -> State; false -> State#state{ - monitors = pmon:monitor({rabbit, Node}, Monitors)} + monitors = pmon:monitor({rabbit, Node}, Monitors)} end, ok = handle_live_rabbit(Node), Partitions1 = lists:usort([Node | Partitions]), @@ -893,4 +893,4 @@ startup_log([]) -> rabbit_log:info("Starting rabbit_node_monitor~n", []); startup_log(Nodes) -> rabbit_log:info("Starting rabbit_node_monitor, might be partitioned from ~p~n", - [Nodes]). + [Nodes]). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_parameter_validation.erl b/deps/rabbit/src/rabbit_parameter_validation.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_parameter_validation.erl rename to deps/rabbit/src/rabbit_parameter_validation.erl index 5eaff34..90ab1d5 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_parameter_validation.erl +++ b/deps/rabbit/src/rabbit_parameter_validation.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_parameter_validation). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_password.erl b/deps/rabbit/src/rabbit_password.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_password.erl rename to deps/rabbit/src/rabbit_password.erl index 02aa62d..b7987df 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_password.erl +++ b/deps/rabbit/src/rabbit_password.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_password). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_md5.erl b/deps/rabbit/src/rabbit_password_hashing_md5.erl similarity index 93% rename from rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_md5.erl rename to deps/rabbit/src/rabbit_password_hashing_md5.erl index ac71bcf..75d8e4e 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_md5.erl +++ b/deps/rabbit/src/rabbit_password_hashing_md5.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% Legacy hashing implementation, only used as a last resort when diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha256.erl b/deps/rabbit/src/rabbit_password_hashing_sha256.erl similarity index 92% rename from rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha256.erl rename to deps/rabbit/src/rabbit_password_hashing_sha256.erl index 9381dbf..5df4d93 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha256.erl +++ b/deps/rabbit/src/rabbit_password_hashing_sha256.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_password_hashing_sha256). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha512.erl b/deps/rabbit/src/rabbit_password_hashing_sha512.erl similarity index 92% rename from rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha512.erl rename to deps/rabbit/src/rabbit_password_hashing_sha512.erl index beb7fa5..5a4b960 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_password_hashing_sha512.erl +++ b/deps/rabbit/src/rabbit_password_hashing_sha512.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_password_hashing_sha512). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_pbe.erl b/deps/rabbit/src/rabbit_pbe.erl similarity index 92% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_pbe.erl rename to deps/rabbit/src/rabbit_pbe.erl index d561415..f4998d4 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_pbe.erl +++ b/deps/rabbit/src/rabbit_pbe.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_pbe). @@ -23,20 +23,12 @@ %% Supported ciphers and hashes supported_ciphers() -> - NotSupportedByUs = [aes_ctr, aes_ecb, des_ecb, blowfish_ecb, rc4, aes_gcm], - SupportedByCrypto = proplists:get_value(ciphers, crypto:supports()), - lists:filter(fun(Cipher) -> - not lists:member(Cipher, NotSupportedByUs) - end, - SupportedByCrypto). + proplists:get_value(ciphers, crypto:supports()) + -- [aes_ctr, aes_ecb, des_ecb, blowfish_ecb, rc4, aes_gcm]. supported_hashes() -> - NotSupportedByUs = [md4, ripemd160], - SupportedByCrypto = proplists:get_value(hashs, crypto:supports()), - lists:filter(fun(Hash) -> - not lists:member(Hash, NotSupportedByUs) - end, - SupportedByCrypto). + proplists:get_value(hashs, crypto:supports()) + -- [md4, ripemd160]. %% Default encryption parameters (keep those in sync with rabbit.app.src) default_cipher() -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_plugins.erl b/deps/rabbit/src/rabbit_plugins.erl similarity index 62% rename from rabbitmq-server/deps/rabbit/src/rabbit_plugins.erl rename to deps/rabbit/src/rabbit_plugins.erl index 7c1217c..4d8966f 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_plugins.erl +++ b/deps/rabbit/src/rabbit_plugins.erl @@ -15,7 +15,7 @@ %% -module(rabbit_plugins). --include_lib("rabbit_common/include/rabbit.hrl"). +-include("rabbit.hrl"). -export([setup/0, active/0, read_enabled/1, list/1, list/2, dependencies/3]). -export([ensure/1]). @@ -61,36 +61,10 @@ ensure(FileJustChanged0) -> {error, {enabled_plugins_mismatch, FileJustChanged, OurFile}} end. --spec plugins_expand_dir() -> file:filename(). -plugins_expand_dir() -> - case application:get_env(rabbit, plugins_expand_dir) of - {ok, ExpandDir} -> - ExpandDir; - _ -> - filename:join([rabbit_mnesia:dir(), "plugins_expand_dir"]) - end. - --spec plugins_dist_dir() -> file:filename(). -plugins_dist_dir() -> - case application:get_env(rabbit, plugins_dir) of - {ok, PluginsDistDir} -> - PluginsDistDir; - _ -> - filename:join([rabbit_mnesia:dir(), "plugins_dir_stub"]) - end. - --spec enabled_plugins() -> [atom()]. -enabled_plugins() -> - case application:get_env(rabbit, enabled_plugins_file) of - {ok, EnabledFile} -> - read_enabled(EnabledFile); - _ -> - [] - end. - %% @doc Prepares the file system and installs all enabled plugins. setup() -> - ExpandDir = plugins_expand_dir(), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), + %% Eliminate the contents of the destination directory case delete_recursively(ExpandDir) of ok -> ok; @@ -98,26 +72,54 @@ setup() -> [ExpandDir, E1]}}) end, - Enabled = enabled_plugins(), + {ok, EnabledFile} = application:get_env(rabbit, enabled_plugins_file), + Enabled = read_enabled(EnabledFile), prepare_plugins(Enabled). %% @doc Lists the plugins which are currently running. active() -> - InstalledPlugins = plugin_names(list(plugins_dist_dir())), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), + InstalledPlugins = plugin_names(list(ExpandDir)), [App || {App, _, _} <- rabbit_misc:which_applications(), lists:member(App, InstalledPlugins)]. %% @doc Get the list of plugins which are ready to be enabled. -list(PluginsPath) -> - list(PluginsPath, false). +list(PluginsDir) -> + list(PluginsDir, false). -list(PluginsPath, IncludeRequiredDeps) -> - {AllPlugins, LoadingProblems} = discover_plugins(split_path(PluginsPath)), - {UniquePlugins, DuplicateProblems} = remove_duplicate_plugins(AllPlugins), - Plugins1 = maybe_keep_required_deps(IncludeRequiredDeps, UniquePlugins), - Plugins2 = remove_otp_overrideable_plugins(Plugins1), - maybe_report_plugin_loading_problems(LoadingProblems ++ DuplicateProblems), - ensure_dependencies(Plugins2). +list(PluginsDir, IncludeRequiredDeps) -> + EZs = [{ez, EZ} || EZ <- filelib:wildcard("*.ez", PluginsDir)], + FreeApps = [{app, App} || + App <- filelib:wildcard("*/ebin/*.app", PluginsDir)], + %% We load the "rabbit" application to be sure we can get the + %% "applications" key. This is required for rabbitmq-plugins for + %% instance. + application:load(rabbit), + {ok, RabbitDeps} = application:get_key(rabbit, applications), + {AvailablePlugins, Problems} = + lists:foldl(fun ({error, EZ, Reason}, {Plugins1, Problems1}) -> + {Plugins1, [{EZ, Reason} | Problems1]}; + (Plugin = #plugin{name = Name}, {Plugins1, Problems1}) -> + %% Applications RabbitMQ depends on (eg. + %% "rabbit_common") can't be considered + %% plugins, otherwise rabbitmq-plugins would + %% list them and the user may believe he can + %% disable them. + case IncludeRequiredDeps orelse + not lists:member(Name, RabbitDeps) of + true -> {[Plugin|Plugins1], Problems1}; + false -> {Plugins1, Problems1} + end + end, {[], []}, + [plugin_info(PluginsDir, Plug) || Plug <- EZs ++ FreeApps]), + case Problems of + [] -> ok; + _ -> rabbit_log:warning( + "Problem reading some plugins: ~p~n", [Problems]) + end, + Plugins = lists:filter(fun(P) -> not plugin_provided_by_otp(P) end, + AvailablePlugins), + ensure_dependencies(Plugins). %% @doc Read the list of enabled plugins from the supplied term file. read_enabled(PluginsFile) -> @@ -187,9 +189,10 @@ is_loadable(App) -> %%---------------------------------------------------------------------------- prepare_plugins(Enabled) -> - ExpandDir = plugins_expand_dir(), + {ok, PluginsDistDir} = application:get_env(rabbit, plugins_dir), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), - AllPlugins = list(plugins_dist_dir()), + AllPlugins = list(PluginsDistDir), Wanted = dependencies(false, Enabled, AllPlugins), WantedPlugins = lookup_plugins(Wanted, AllPlugins), @@ -200,10 +203,13 @@ prepare_plugins(Enabled) -> end, [prepare_plugin(Plugin, ExpandDir) || Plugin <- WantedPlugins], + + [prepare_dir_plugin(PluginAppDescPath) || + PluginAppDescPath <- filelib:wildcard(ExpandDir ++ "/*/ebin/*.app")], Wanted. clean_plugins(Plugins) -> - ExpandDir = plugins_expand_dir(), + {ok, ExpandDir} = application:get_env(rabbit, plugins_expand_dir), [clean_plugin(Plugin, ExpandDir) || Plugin <- Plugins]. clean_plugin(Plugin, ExpandDir) -> @@ -247,44 +253,20 @@ delete_recursively(Fn) -> {error, {Path, E}} -> {error, {cannot_delete, Path, E}} end. -find_unzipped_app_file(ExpandDir, Files) -> - StripComponents = length(filename:split(ExpandDir)), - [ X || X <- Files, - [_AppName, "ebin", MaybeAppFile] <- - [lists:nthtail(StripComponents, filename:split(X))], - lists:suffix(".app", MaybeAppFile) - ]. - -prepare_plugin(#plugin{type = ez, name = Name, location = Location}, ExpandDir) -> - case zip:unzip(Location, [{cwd, ExpandDir}]) of - {ok, Files} -> - case find_unzipped_app_file(ExpandDir, Files) of - [PluginAppDescPath|_] -> - prepare_dir_plugin(PluginAppDescPath); - _ -> - rabbit_log:error("Plugin archive '~s' doesn't contain an .app file~n", [Location]), - throw({app_file_missing, Name, Location}) - end; - {error, Reason} -> - rabbit_log:error("Could not unzip plugin archive '~s': ~p~n", [Location, Reason]), - throw({failed_to_unzip_plugin, Name, Location, Reason}) - end; -prepare_plugin(#plugin{type = dir, location = Location, name = Name}, - _ExpandDir) -> - case filelib:wildcard(Location ++ "/ebin/*.app") of - [PluginAppDescPath|_] -> - prepare_dir_plugin(PluginAppDescPath); - _ -> - rabbit_log:error("Plugin directory '~s' doesn't contain an .app file~n", [Location]), - throw({app_file_missing, Name, Location}) - end. +prepare_plugin(#plugin{type = ez, location = Location}, ExpandDir) -> + zip:unzip(Location, [{cwd, ExpandDir}]); +prepare_plugin(#plugin{type = dir, name = Name, location = Location}, + ExpandDir) -> + rabbit_file:recursive_copy(Location, filename:join([ExpandDir, Name])). -plugin_info({ez, EZ}) -> +plugin_info(Base, {ez, EZ0}) -> + EZ = filename:join([Base, EZ0]), case read_app_file(EZ) of {application, Name, Props} -> mkplugin(Name, Props, ez, EZ); {error, Reason} -> {error, EZ, Reason} end; -plugin_info({app, App}) -> +plugin_info(Base, {app, App0}) -> + App = filename:join([Base, App0]), case rabbit_file:read_term_file(App) of {ok, [{application, Name, Props}]} -> mkplugin(Name, Props, dir, @@ -335,93 +317,3 @@ plugin_names(Plugins) -> lookup_plugins(Names, AllPlugins) -> [P || P = #plugin{name = Name} <- AllPlugins, lists:member(Name, Names)]. - -%% Split PATH-like value into its components. -split_path(PathString) -> - Delimiters = case os:type() of - {unix, _} -> ":"; - {win32, _} -> ";" - end, - string:tokens(PathString, Delimiters). - -%% Search for files using glob in a given dir. Returns full filenames of those files. -full_path_wildcard(Glob, Dir) -> - [filename:join([Dir, File]) || File <- filelib:wildcard(Glob, Dir)]. - -%% Returns list off all .ez files in a given set of directories -list_ezs([]) -> - []; -list_ezs([Dir|Rest]) -> - [{ez, EZ} || EZ <- full_path_wildcard("*.ez", Dir)] ++ list_ezs(Rest). - -%% Returns list of all files that look like OTP applications in a -%% given set of directories. -list_free_apps([]) -> - []; -list_free_apps([Dir|Rest]) -> - [{app, App} || App <- full_path_wildcard("*/ebin/*.app", Dir)] - ++ list_free_apps(Rest). - -compare_by_name_and_version(#plugin{name = Name, version = VersionA}, - #plugin{name = Name, version = VersionB}) -> - ec_semver:lte(VersionA, VersionB); -compare_by_name_and_version(#plugin{name = NameA}, - #plugin{name = NameB}) -> - NameA =< NameB. - --spec discover_plugins([Directory]) -> {[#plugin{}], [Problem]} when - Directory :: file:name(), - Problem :: {file:name(), term()}. -discover_plugins(PluginsDirs) -> - EZs = list_ezs(PluginsDirs), - FreeApps = list_free_apps(PluginsDirs), - read_plugins_info(EZs ++ FreeApps, {[], []}). - -read_plugins_info([], Acc) -> - Acc; -read_plugins_info([Path|Paths], {Plugins, Problems}) -> - case plugin_info(Path) of - #plugin{} = Plugin -> - read_plugins_info(Paths, {[Plugin|Plugins], Problems}); - {error, Location, Reason} -> - read_plugins_info(Paths, {Plugins, [{Location, Reason}|Problems]}) - end. - -remove_duplicate_plugins(Plugins) -> - %% Reverse order ensures that if there are several versions of the - %% same plugin, the most recent one comes first. - Sorted = lists:reverse( - lists:sort(fun compare_by_name_and_version/2, Plugins)), - remove_duplicate_plugins(Sorted, {[], []}). - -remove_duplicate_plugins([], Acc) -> - Acc; -remove_duplicate_plugins([Best = #plugin{name = Name}, Offender = #plugin{name = Name} | Rest], - {Plugins0, Problems0}) -> - Problems1 = [{Offender#plugin.location, duplicate_plugin}|Problems0], - remove_duplicate_plugins([Best|Rest], {Plugins0, Problems1}); -remove_duplicate_plugins([Plugin|Rest], {Plugins0, Problems0}) -> - Plugins1 = [Plugin|Plugins0], - remove_duplicate_plugins(Rest, {Plugins1, Problems0}). - -maybe_keep_required_deps(true, Plugins) -> - Plugins; -maybe_keep_required_deps(false, Plugins) -> - %% We load the "rabbit" application to be sure we can get the - %% "applications" key. This is required for rabbitmq-plugins for - %% instance. - application:load(rabbit), - {ok, RabbitDeps} = application:get_key(rabbit, applications), - lists:filter(fun(#plugin{name = Name}) -> - not lists:member(Name, RabbitDeps) - end, - Plugins). - -remove_otp_overrideable_plugins(Plugins) -> - lists:filter(fun(P) -> not plugin_provided_by_otp(P) end, - Plugins). - -maybe_report_plugin_loading_problems([]) -> - ok; -maybe_report_plugin_loading_problems(Problems) -> - rabbit_log:warning("Problem reading some plugins: ~p~n", [Problems]). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_plugins_main.erl b/deps/rabbit/src/rabbit_plugins_main.erl similarity index 89% rename from rabbitmq-server/deps/rabbit/src/rabbit_plugins_main.erl rename to deps/rabbit/src/rabbit_plugins_main.erl index 758a9ac..ff51626 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_plugins_main.erl +++ b/deps/rabbit/src/rabbit_plugins_main.erl @@ -169,9 +169,9 @@ format_plugins(Node, Pattern, Opts, #cli{all = All, EnabledImplicitly = Implicit -- Enabled, {StatusMsg, Running} = - case remote_running_plugins(Node) of - {ok, Active} -> {"* = running on ~s", Active}; - error -> {"[failed to contact ~s - status not shown]", []} + case rabbit_misc:rpc_call(Node, rabbit_plugins, active, []) of + {badrpc, _} -> {"[failed to contact ~s - status not shown]", []}; + Active -> {"* = running on ~s", Active} end, {ok, RE} = re:compile(Pattern), Plugins = [ Plugin || @@ -196,7 +196,7 @@ format_plugins(Node, Pattern, Opts, #cli{all = All, Format, MaxWidth) || P <- Plugins1], ok. -format_plugin(#plugin{name = Name, version = OnDiskVersion, +format_plugin(#plugin{name = Name, version = Version, description = Description, dependencies = Deps}, Enabled, EnabledImplicitly, Running, Format, MaxWidth) -> @@ -206,7 +206,7 @@ format_plugin(#plugin{name = Name, version = OnDiskVersion, {false, true} -> "e"; _ -> " " end, - RunningGlyph = case lists:keymember(Name, 1, Running) of + RunningGlyph = case lists:member(Name, Running) of true -> "*"; false -> " " end, @@ -214,7 +214,6 @@ format_plugin(#plugin{name = Name, version = OnDiskVersion, Opt = fun (_F, A, A) -> ok; ( F, A, _) -> io:format(F, [A]) end, - Version = format_running_plugin_version(Name, OnDiskVersion, Running), case Format of minimal -> io:format("~s~n", [Name]); normal -> io:format("~s ~-" ++ integer_to_list(MaxWidth) ++ "w ", @@ -306,31 +305,3 @@ rpc_call(Node, Online, Mod, Fun, Args) -> plur([_]) -> ""; plur(_) -> "s". - --spec remote_running_plugins(node()) -> [{atom(), Vsn :: string()}]. -remote_running_plugins(Node) -> - case rabbit_misc:rpc_call(Node, rabbit_plugins, active, []) of - {badrpc, _} -> error; - Active -> maybe_augment_with_versions(Node, Active) - end. - --spec maybe_augment_with_versions(node(), [atom()]) -> [{atom(), Vsn :: string()}]. -maybe_augment_with_versions(Node, Plugins) -> - case rabbit_misc:rpc_call(Node, rabbit_misc, which_applications, []) of - {badrpc, _} -> - error; - All -> - {ok, [{App, Vsn} || {App, _, Vsn} <- All, - lists:member(App, Plugins)]} - end. - --spec format_running_plugin_version(atom(), string(), [{atom(), Vsn :: string()}]) -> string(). -format_running_plugin_version(Name, OnDiskVersion, RunningPlugins) -> - case lists:keyfind(Name, 1, RunningPlugins) of - false -> - OnDiskVersion; - {_, OnDiskVersion} -> - OnDiskVersion; - {_, RunningVersion} -> - io_lib:format("~s (pending upgrade to ~s)", [RunningVersion, OnDiskVersion]) - end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_policies.erl b/deps/rabbit/src/rabbit_policies.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_policies.erl rename to deps/rabbit/src/rabbit_policies.erl index b554942..c7d4c99 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_policies.erl +++ b/deps/rabbit/src/rabbit_policies.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_policies). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_policy.erl b/deps/rabbit/src/rabbit_policy.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_policy.erl rename to deps/rabbit/src/rabbit_policy.erl index 93cd90f..a9caadf 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_policy.erl +++ b/deps/rabbit/src/rabbit_policy.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_policy). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_prelaunch.erl b/deps/rabbit/src/rabbit_prelaunch.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_prelaunch.erl rename to deps/rabbit/src/rabbit_prelaunch.erl index ec4a039..569a8d6 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_prelaunch.erl +++ b/deps/rabbit/src/rabbit_prelaunch.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_prelaunch). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_prequeue.erl b/deps/rabbit/src/rabbit_prequeue.erl similarity index 100% rename from rabbitmq-server/deps/rabbit/src/rabbit_prequeue.erl rename to deps/rabbit/src/rabbit_prequeue.erl diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_priority_queue.erl b/deps/rabbit/src/rabbit_priority_queue.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_priority_queue.erl rename to deps/rabbit/src/rabbit_priority_queue.erl index 34e2326..b7a3afd 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_priority_queue.erl +++ b/deps/rabbit/src/rabbit_priority_queue.erl @@ -657,7 +657,7 @@ cse(_, lazy) -> lazy; cse(lazy, _) -> lazy; %% numerical stats cse(A, B) when is_number(A) -> A + B; -cse({delta, _, _, _, _}, _) -> {delta, todo, todo, todo, todo}; +cse({delta, _, _, _}, _) -> {delta, todo, todo, todo}; cse(A, B) -> exit({A, B}). %% When asked about 'head_message_timestamp' fro this priority queue, we diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_consumers.erl b/deps/rabbit/src/rabbit_queue_consumers.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_consumers.erl rename to deps/rabbit/src/rabbit_queue_consumers.erl index 567a735..a800239 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_consumers.erl +++ b/deps/rabbit/src/rabbit_queue_consumers.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_consumers). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_index.erl b/deps/rabbit/src/rabbit_queue_index.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_index.erl rename to deps/rabbit/src/rabbit_queue_index.erl index 5a0f76a..6a14854 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_index.erl +++ b/deps/rabbit/src/rabbit_queue_index.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_index). @@ -123,7 +123,7 @@ -define(SEGMENT_EXTENSION, ".idx"). %% TODO: The segment size would be configurable, but deriving all the -%% other values is quite hairy and quite possibly noticeably less +%% other values is quite hairy and quite possibly noticably less %% efficient, depending on how clever the compiler is when it comes to %% binary generation/matching with constant vs variable lengths. @@ -176,40 +176,13 @@ %%---------------------------------------------------------------------------- --record(qistate, { - %% queue directory where segment and journal files are stored - dir, - %% map of #segment records - segments, - %% journal file handle obtained from/used by file_handle_cache - journal_handle, - %% how many not yet flushed entries are there - dirty_count, - %% this many not yet flushed journal entries will force a flush - max_journal_entries, - %% callback function invoked when a message is "handled" - %% by the index and potentially can be confirmed to the publisher - on_sync, - on_sync_msg, - %% set of IDs of unconfirmed [to publishers] messages - unconfirmed, - unconfirmed_msg, - %% optimisation - pre_publish_cache, - %% optimisation - delivered_cache}). - --record(segment, { - %% segment ID (an integer) - num, - %% segment file path (see also ?SEGMENT_EXTENSION) - path, - %% index operation log entries in this segment - journal_entries, - entries_to_segment, - %% counter of unacknowledged messages - unacked -}). +-record(qistate, {dir, segments, journal_handle, dirty_count, + max_journal_entries, on_sync, on_sync_msg, + unconfirmed, unconfirmed_msg, + pre_publish_cache, delivered_cache}). + +-record(segment, {num, path, journal_entries, + entries_to_segment, unacked}). -include("rabbit.hrl"). @@ -653,7 +626,7 @@ recover_message(false, _, no_del, RelSeq, {Segment, DirtyCount}) -> DirtyCount + 2}. queue_name_to_dir_name(Name = #resource { kind = queue }) -> - <> = erlang:md5(term_to_binary_compat:term_to_binary_1(Name)), + <> = erlang:md5(term_to_binary(Name)), rabbit_misc:format("~.36B", [Num]). queues_dir() -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_client_local.erl b/deps/rabbit/src/rabbit_queue_location_client_local.erl similarity index 95% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_location_client_local.erl rename to deps/rabbit/src/rabbit_queue_location_client_local.erl index 0d4af99..cd7dfdd 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_client_local.erl +++ b/deps/rabbit/src/rabbit_queue_location_client_local.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_location_client_local). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_min_masters.erl b/deps/rabbit/src/rabbit_queue_location_min_masters.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_location_min_masters.erl rename to deps/rabbit/src/rabbit_queue_location_min_masters.erl index a1e73ee..bc112a3 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_min_masters.erl +++ b/deps/rabbit/src/rabbit_queue_location_min_masters.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_location_min_masters). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_random.erl b/deps/rabbit/src/rabbit_queue_location_random.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_location_random.erl rename to deps/rabbit/src/rabbit_queue_location_random.erl index 3a3a236..2579cbb 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_random.erl +++ b/deps/rabbit/src/rabbit_queue_location_random.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_location_random). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_validator.erl b/deps/rabbit/src/rabbit_queue_location_validator.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_location_validator.erl rename to deps/rabbit/src/rabbit_queue_location_validator.erl index 2b0f8c7..c5aad50 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_location_validator.erl +++ b/deps/rabbit/src/rabbit_queue_location_validator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_location_validator). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_master_location_misc.erl b/deps/rabbit/src/rabbit_queue_master_location_misc.erl similarity index 94% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_master_location_misc.erl rename to deps/rabbit/src/rabbit_queue_master_location_misc.erl index 0b9efdd..3d5b2cd 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_master_location_misc.erl +++ b/deps/rabbit/src/rabbit_queue_master_location_misc.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_master_location_misc). @@ -63,8 +63,8 @@ get_location(Queue=#amqqueue{})-> end. get_location_mod_by_args(#amqqueue{arguments=Args}) -> - case rabbit_misc:table_lookup(Args, <<"x-queue-master-locator">>) of - {_Type, Strategy} -> + case proplists:lookup(<<"x-queue-master-locator">> , Args) of + {<<"x-queue-master-locator">> , Strategy} -> case rabbit_queue_location_validator:validate_strategy(Strategy) of Reply = {ok, _CB} -> Reply; Error -> Error diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_recovery_terms.erl b/deps/rabbit/src/rabbit_recovery_terms.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_recovery_terms.erl rename to deps/rabbit/src/rabbit_recovery_terms.erl index c941126..f6f94ec 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_recovery_terms.erl +++ b/deps/rabbit/src/rabbit_recovery_terms.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% We use a gen_server simply so that during the terminate/2 call diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_registry.erl b/deps/rabbit/src/rabbit_registry.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_registry.erl rename to deps/rabbit/src/rabbit_registry.erl index 33ff15d..0428c35 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_registry.erl +++ b/deps/rabbit/src/rabbit_registry.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_registry). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_resource_monitor_misc.erl b/deps/rabbit/src/rabbit_resource_monitor_misc.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_resource_monitor_misc.erl rename to deps/rabbit/src/rabbit_resource_monitor_misc.erl index 8d743b9..56faefe 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_resource_monitor_misc.erl +++ b/deps/rabbit/src/rabbit_resource_monitor_misc.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_restartable_sup.erl b/deps/rabbit/src/rabbit_restartable_sup.erl similarity index 95% rename from rabbitmq-server/deps/rabbit/src/rabbit_restartable_sup.erl rename to deps/rabbit/src/rabbit_restartable_sup.erl index 14b8fd9..1960259 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_restartable_sup.erl +++ b/deps/rabbit/src/rabbit_restartable_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_restartable_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_router.erl b/deps/rabbit/src/rabbit_router.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_router.erl rename to deps/rabbit/src/rabbit_router.erl index 1f3017f..d4390ac 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_router.erl +++ b/deps/rabbit/src/rabbit_router.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_router). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_runtime_parameters.erl b/deps/rabbit/src/rabbit_runtime_parameters.erl similarity index 80% rename from rabbitmq-server/deps/rabbit/src/rabbit_runtime_parameters.erl rename to deps/rabbit/src/rabbit_runtime_parameters.erl index bea1626..97f78da 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_runtime_parameters.erl +++ b/deps/rabbit/src/rabbit_runtime_parameters.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_runtime_parameters). @@ -27,7 +27,7 @@ %% %% The most obvious use case for runtime parameters is policies but %% there are others: -%% +%% %% * Plugin-specific parameters that only make sense at runtime, %% e.g. Federation and Shovel link settings %% * Exchange and queue decorators @@ -40,8 +40,6 @@ %% Parameters are stored in Mnesia and can be global. Their changes %% are broadcasted over rabbit_event. %% -%% Global parameters keys are atoms and values are JSON documents. -%% %% See also: %% %% * rabbit_policies @@ -55,9 +53,7 @@ list_component/1, list/2, list_formatted/1, list_formatted/3, lookup/3, value/3, value/4, info_keys/0, clear_component/1]). --export([parse_set_global/2, set_global/2, value_global/1, value_global/2, - list_global/0, list_global_formatted/0, list_global_formatted/2, - lookup_global/1, global_info_keys/0, clear_global/1]). +-export([set_global/2, value_global/1, value_global/2]). %%---------------------------------------------------------------------------- @@ -112,17 +108,10 @@ set(_, <<"policy">>, _, _, _) -> set(VHost, Component, Name, Term, User) -> set_any(VHost, Component, Name, Term, User). -parse_set_global(Name, String) -> - case rabbit_misc:json_decode(String) of - {ok, JSON} -> set_global(Name, rabbit_misc:json_to_term(JSON)); - error -> {error_string, "JSON decoding error"} - end. - -set_global(Name, Term) -> - NameAsAtom = rabbit_data_coercion:to_atom(Name), - mnesia_update(NameAsAtom, Term), - event_notify(parameter_set, none, global, [{name, NameAsAtom}, - {value, Term}]), +set_global(Name, Term) -> + mnesia_update(Name, Term), + event_notify(parameter_set, none, global, [{name, Name}, + {value, Term}]), ok. format_error(L) -> @@ -178,34 +167,14 @@ clear(_, <<"policy">> , _) -> clear(VHost, Component, Name) -> clear_any(VHost, Component, Name). -clear_global(Key) -> - KeyAsAtom = rabbit_data_coercion:to_atom(Key), - Notify = fun() -> - event_notify(parameter_set, none, global, [{name, KeyAsAtom}]), - ok - end, - case value_global(KeyAsAtom) of - not_found -> - {error_string, "Parameter does not exist"}; - _ -> - F = fun () -> - ok = mnesia:delete(?TABLE, KeyAsAtom, write) - end, - ok = rabbit_misc:execute_mnesia_transaction(F), - case mnesia:is_transaction() of - true -> Notify; - false -> Notify() - end - end. - clear_component(Component) -> - case list_component(Component) of + case rabbit_runtime_parameters:list_component(Component) of [] -> ok; Xs -> - [clear(pget(vhost, X), - pget(component, X), - pget(name, X)) || X <- Xs], + [rabbit_runtime_parameters:clear(pget(vhost, X), + pget(component, X), + pget(name, X))|| X <- Xs], ok end. @@ -265,30 +234,13 @@ list(VHost, Component) -> Comp =/= <<"policy">> orelse Component =:= <<"policy">>] end). -list_global() -> - %% list only atom keys - mnesia:async_dirty( - fun () -> - Match = #runtime_parameters{key = '_', _ = '_'}, - [p(P) || P <- mnesia:match_object(?TABLE, Match, read), - is_atom(P#runtime_parameters.key)] - end). - list_formatted(VHost) -> [pset(value, format(pget(value, P)), P) || P <- list(VHost)]. list_formatted(VHost, Ref, AggregatorPid) -> rabbit_control_misc:emitting_map( - AggregatorPid, Ref, - fun(P) -> pset(value, format(pget(value, P)), P) end, list(VHost)). - -list_global_formatted() -> - [pset(value, format(pget(value, P)), P) || P <- list_global()]. - -list_global_formatted(Ref, AggregatorPid) -> - rabbit_control_misc:emitting_map( - AggregatorPid, Ref, - fun(P) -> pset(value, format(pget(value, P)), P) end, list_global()). + AggregatorPid, Ref, + fun(P) -> pset(value, format(pget(value, P)), P) end, list(VHost)). lookup(VHost, Component, Name) -> case lookup0({VHost, Component, Name}, rabbit_misc:const(not_found)) of @@ -296,20 +248,11 @@ lookup(VHost, Component, Name) -> Params -> p(Params) end. -lookup_global(Name) -> - case lookup0(Name, rabbit_misc:const(not_found)) of - not_found -> not_found; - Params -> p(Params) - end. - value(VHost, Comp, Name) -> value0({VHost, Comp, Name}). value(VHost, Comp, Name, Def) -> value0({VHost, Comp, Name}, Def). -value_global(Key) -> - value0(Key). - -value_global(Key, Default) -> - value0(Key, Default). +value_global(Key) -> value0(Key). +value_global(Key, Default) -> value0(Key, Default). value0(Key) -> case lookup0(Key, rabbit_misc:const(not_found)) of @@ -346,16 +289,10 @@ p(#runtime_parameters{key = {VHost, Component, Name}, value = Value}) -> [{vhost, VHost}, {component, Component}, {name, Name}, - {value, Value}]; - -p(#runtime_parameters{key = Key, value = Value}) when is_atom(Key) -> - [{name, Key}, {value, Value}]. info_keys() -> [component, name, value]. -global_info_keys() -> [name, value]. - %%--------------------------------------------------------------------------- lookup_component(Component) -> @@ -368,7 +305,7 @@ lookup_component(Component) -> format(Term) -> {ok, JSON} = rabbit_misc:json_encode(rabbit_misc:term_to_json(Term)), - iolist_to_binary(JSON). + list_to_binary(JSON). flatten_errors(L) -> case [{F, A} || I <- lists:flatten([L]), {error, F, A} <- [I]] of diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_sasl_report_file_h.erl b/deps/rabbit/src/rabbit_sasl_report_file_h.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_sasl_report_file_h.erl rename to deps/rabbit/src/rabbit_sasl_report_file_h.erl index 8ee223c..9c6d765 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_sasl_report_file_h.erl +++ b/deps/rabbit/src/rabbit_sasl_report_file_h.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sasl_report_file_h). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_cert_info.erl b/deps/rabbit/src/rabbit_ssl.erl similarity index 84% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_cert_info.erl rename to deps/rabbit/src/rabbit_ssl.erl index 94a0250..ac9fb20 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_cert_info.erl +++ b/deps/rabbit/src/rabbit_ssl.erl @@ -11,17 +11,17 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% --module(rabbit_cert_info). +-module(rabbit_ssl). + +-include("rabbit.hrl"). -include_lib("public_key/include/public_key.hrl"). --export([issuer/1, - subject/1, - validity/1, - subject_items/2]). +-export([peer_cert_issuer/1, peer_cert_subject/1, peer_cert_validity/1]). +-export([peer_cert_subject_items/2, peer_cert_auth_name/1]). %%-------------------------------------------------------------------------- @@ -29,14 +29,20 @@ -type certificate() :: binary(). +-spec peer_cert_issuer(certificate()) -> string(). +-spec peer_cert_subject(certificate()) -> string(). +-spec peer_cert_validity(certificate()) -> string(). +-spec peer_cert_subject_items + (certificate(), tuple()) -> [string()] | 'not_found'. +-spec peer_cert_auth_name + (certificate()) -> binary() | 'not_found' | 'unsafe'. + %%-------------------------------------------------------------------------- %% High-level functions used by reader %%-------------------------------------------------------------------------- %% Return a string describing the certificate's issuer. --spec issuer(certificate()) -> string(). - -issuer(Cert) -> +peer_cert_issuer(Cert) -> cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { issuer = Issuer }}) -> @@ -44,9 +50,7 @@ issuer(Cert) -> end, Cert). %% Return a string describing the certificate's subject, as per RFC4514. --spec subject(certificate()) -> string(). - -subject(Cert) -> +peer_cert_subject(Cert) -> cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { subject = Subject }}) -> @@ -54,10 +58,7 @@ subject(Cert) -> end, Cert). %% Return the parts of the certificate's subject. --spec subject_items - (certificate(), tuple()) -> [string()] | 'not_found'. - -subject_items(Cert, Type) -> +peer_cert_subject_items(Cert, Type) -> cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { subject = Subject }}) -> @@ -65,9 +66,7 @@ subject_items(Cert, Type) -> end, Cert). %% Return a string describing the certificate's validity. --spec validity(certificate()) -> string(). - -validity(Cert) -> +peer_cert_validity(Cert) -> cert_info(fun(#'OTPCertificate' { tbsCertificate = #'OTPTBSCertificate' { validity = {'Validity', Start, End} }}) -> @@ -75,6 +74,39 @@ validity(Cert) -> format_asn1_value(End)]) end, Cert). +%% Extract a username from the certificate +peer_cert_auth_name(Cert) -> + {ok, Mode} = application:get_env(rabbit, ssl_cert_login_from), + peer_cert_auth_name(Mode, Cert). + +peer_cert_auth_name(distinguished_name, Cert) -> + case auth_config_sane() of + true -> iolist_to_binary(peer_cert_subject(Cert)); + false -> unsafe + end; + +peer_cert_auth_name(common_name, Cert) -> + %% If there is more than one CN then we join them with "," in a + %% vaguely DN-like way. But this is more just so we do something + %% more intelligent than crashing, if you actually want to escape + %% things properly etc, use DN mode. + case auth_config_sane() of + true -> case peer_cert_subject_items(Cert, ?'id-at-commonName') of + not_found -> not_found; + CNs -> list_to_binary(string:join(CNs, ",")) + end; + false -> unsafe + end. + +auth_config_sane() -> + {ok, Opts} = application:get_env(rabbit, ssl_options), + case proplists:get_value(verify, Opts) of + verify_peer -> true; + V -> rabbit_log:warning("SSL certificate authentication " + "disabled, verify=~p~n", [V]), + false + end. + %%-------------------------------------------------------------------------- cert_info(F, Cert) -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_sup.erl b/deps/rabbit/src/rabbit_sup.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_sup.erl rename to deps/rabbit/src/rabbit_sup.erl index 4890616..ad70540 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_sup.erl +++ b/deps/rabbit/src/rabbit_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sup). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_table.erl b/deps/rabbit/src/rabbit_table.erl similarity index 84% rename from rabbitmq-server/deps/rabbit/src/rabbit_table.erl rename to deps/rabbit/src/rabbit_table.erl index 8a3766f..3909096 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_table.erl +++ b/deps/rabbit/src/rabbit_table.erl @@ -11,32 +11,29 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_table). --export([create/0, create_local_copy/1, wait_for_replicated/1, wait/1, +-export([create/0, create_local_copy/1, wait_for_replicated/0, wait/1, force_load/0, is_present/0, is_empty/0, needs_default_data/0, - check_schema_integrity/1, clear_ram_only_tables/0, retry_timeout/0, - wait_for_replicated/0]). + check_schema_integrity/0, clear_ram_only_tables/0, wait_timeout/0]). -include("rabbit.hrl"). %%---------------------------------------------------------------------------- --type retry() :: boolean(). -spec create() -> 'ok'. -spec create_local_copy('disc' | 'ram') -> 'ok'. --spec wait_for_replicated(retry()) -> 'ok'. -spec wait_for_replicated() -> 'ok'. -spec wait([atom()]) -> 'ok'. --spec retry_timeout() -> {non_neg_integer() | infinity, non_neg_integer()}. +-spec wait_timeout() -> non_neg_integer() | infinity. -spec force_load() -> 'ok'. -spec is_present() -> boolean(). -spec is_empty() -> boolean(). -spec needs_default_data() -> boolean(). --spec check_schema_integrity(retry()) -> rabbit_types:ok_or_error(any()). +-spec check_schema_integrity() -> rabbit_types:ok_or_error(any()). -spec clear_ram_only_tables() -> 'ok'. %%---------------------------------------------------------------------------- @@ -66,58 +63,25 @@ create_local_copy(ram) -> create_local_copies(ram), create_local_copy(schema, ram_copies). -%% This arity only exists for backwards compatibility with certain -%% plugins. See https://github.com/rabbitmq/rabbitmq-clusterer/issues/19. wait_for_replicated() -> - wait_for_replicated(false). - -wait_for_replicated(Retry) -> wait([Tab || {Tab, TabDef} <- definitions(), - not lists:member({local_content, true}, TabDef)], Retry). + not lists:member({local_content, true}, TabDef)]). wait(TableNames) -> - wait(TableNames, _Retry = false). - -wait(TableNames, Retry) -> - {Timeout, Retries} = retry_timeout(Retry), - wait(TableNames, Timeout, Retries). - -wait(TableNames, Timeout, Retries) -> %% We might be in ctl here for offline ops, in which case we can't %% get_env() for the rabbit app. - rabbit_log:info("Waiting for Mnesia tables for ~p ms, ~p retries left~n", - [Timeout, Retries - 1]), - Result = case mnesia:wait_for_tables(TableNames, Timeout) of - ok -> - ok; - {timeout, BadTabs} -> - {error, {timeout_waiting_for_tables, BadTabs}}; - {error, Reason} -> - {error, {failed_waiting_for_tables, Reason}} - end, - case {Retries, Result} of - {_, ok} -> + Timeout = wait_timeout(), + case mnesia:wait_for_tables(TableNames, Timeout) of + ok -> ok; - {1, {error, _} = Error} -> - throw(Error); - {_, {error, Error}} -> - rabbit_log:warning("Error while waiting for Mnesia tables: ~p~n", [Error]), - wait(TableNames, Timeout, Retries - 1); - _ -> - wait(TableNames, Timeout, Retries - 1) + {timeout, BadTabs} -> + throw({error, {timeout_waiting_for_tables, BadTabs}}); + {error, Reason} -> + throw({error, {failed_waiting_for_tables, Reason}}) end. -retry_timeout(_Retry = false) -> - {retry_timeout(), 1}; -retry_timeout(_Retry = true) -> - Retries = case application:get_env(rabbit, mnesia_table_loading_retry_limit) of - {ok, T} -> T; - undefined -> 10 - end, - {retry_timeout(), Retries}. - -retry_timeout() -> - case application:get_env(rabbit, mnesia_table_loading_retry_timeout) of +wait_timeout() -> + case application:get_env(rabbit, mnesia_table_loading_timeout) of {ok, T} -> T; undefined -> 30000 end. @@ -134,7 +98,7 @@ is_empty(Names) -> lists:all(fun (Tab) -> mnesia:dirty_first(Tab) == '$end_of_table' end, Names). -check_schema_integrity(Retry) -> +check_schema_integrity() -> Tables = mnesia:system_info(tables), case check(fun (Tab, TabDef) -> case lists:member(Tab, Tables) of @@ -142,7 +106,7 @@ check_schema_integrity(Retry) -> true -> check_attributes(Tab, TabDef) end end) of - ok -> wait(names(), Retry), + ok -> ok = wait(names()), check(fun check_content/2); Other -> Other end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_trace.erl b/deps/rabbit/src/rabbit_trace.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_trace.erl rename to deps/rabbit/src/rabbit_trace.erl index 5b8676b..4bfd94e 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_trace.erl +++ b/deps/rabbit/src/rabbit_trace.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_trace). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_upgrade.erl b/deps/rabbit/src/rabbit_upgrade.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_upgrade.erl rename to deps/rabbit/src/rabbit_upgrade.erl index 5452132..f88b7cc 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_upgrade.erl +++ b/deps/rabbit/src/rabbit_upgrade.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_upgrade). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_upgrade_functions.erl b/deps/rabbit/src/rabbit_upgrade_functions.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_upgrade_functions.erl rename to deps/rabbit/src/rabbit_upgrade_functions.erl index 83a1056..8609a0e 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_upgrade_functions.erl +++ b/deps/rabbit/src/rabbit_upgrade_functions.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_upgrade_functions). @@ -19,12 +19,11 @@ %% If you are tempted to add include("rabbit.hrl"). here, don't. Using record %% defs here leads to pain later. --compile([nowarn_export_all, export_all]). +-compile([export_all]). -rabbit_upgrade({remove_user_scope, mnesia, []}). -rabbit_upgrade({hash_passwords, mnesia, []}). -rabbit_upgrade({add_ip_to_listener, mnesia, []}). --rabbit_upgrade({add_opts_to_listener, mnesia, [add_ip_to_listener]}). -rabbit_upgrade({internal_exchanges, mnesia, []}). -rabbit_upgrade({user_to_internal_user, mnesia, [hash_passwords]}). -rabbit_upgrade({topic_trie, mnesia, []}). @@ -60,7 +59,6 @@ -spec remove_user_scope() -> 'ok'. -spec hash_passwords() -> 'ok'. -spec add_ip_to_listener() -> 'ok'. --spec add_opts_to_listener() -> 'ok'. -spec internal_exchanges() -> 'ok'. -spec user_to_internal_user() -> 'ok'. -spec topic_trie() -> 'ok'. @@ -125,14 +123,6 @@ add_ip_to_listener() -> end, [node, protocol, host, ip_address, port]). -add_opts_to_listener() -> - transform( - rabbit_listener, - fun ({listener, Node, Protocol, Host, IP, Port}) -> - {listener, Node, Protocol, Host, IP, Port, []} - end, - [node, protocol, host, ip_address, port, opts]). - internal_exchanges() -> Tables = [rabbit_exchange, rabbit_durable_exchange], AddInternalFun = diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_variable_queue.erl b/deps/rabbit/src/rabbit_variable_queue.erl similarity index 94% rename from rabbitmq-server/deps/rabbit/src/rabbit_variable_queue.erl rename to deps/rabbit/src/rabbit_variable_queue.erl index de1fdbf..dd92256 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_variable_queue.erl +++ b/deps/rabbit/src/rabbit_variable_queue.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_variable_queue). @@ -283,7 +283,6 @@ unacked_bytes, persistent_count, %% w unacked persistent_bytes, %% w unacked - delta_transient_bytes, %% target_ram_count, ram_msg_count, %% w/o unacked @@ -331,7 +330,6 @@ -record(delta, { start_seq_id, %% start_seq_id is inclusive count, - transient, end_seq_id %% end_seq_id is exclusive }). @@ -417,11 +415,9 @@ -define(BLANK_DELTA, #delta { start_seq_id = undefined, count = 0, - transient = 0, end_seq_id = undefined }). -define(BLANK_DELTA_PATTERN(Z), #delta { start_seq_id = Z, count = 0, - transient = 0, end_seq_id = Z }). -define(MICROS_PER_SECOND, 1000000.0). @@ -436,28 +432,21 @@ %% rabbit_amqqueue_process need fairly fresh rates. -define(MSGS_PER_RATE_CALC, 100). + %% we define the garbage collector threshold -%% it needs to tune the `reduce_memory_use` calls. Thus, the garbage collection. -%% see: rabbitmq-server-973 and rabbitmq-server-964 --define(DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD, 1000). --define(EXPLICIT_GC_RUN_OP_THRESHOLD(Mode), +%% it needs to tune the GC calls inside `reduce_memory_use` +%% see: rabbitmq-server-973 and `maybe_execute_gc` function +-define(DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD, 250). +-define(EXPLICIT_GC_RUN_OP_THRESHOLD, case get(explicit_gc_run_operation_threshold) of undefined -> - Val = explicit_gc_run_operation_threshold_for_mode(Mode), + Val = rabbit_misc:get_env(rabbit, lazy_queue_explicit_gc_run_operation_threshold, + ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD), put(explicit_gc_run_operation_threshold, Val), Val; Val -> Val end). -explicit_gc_run_operation_threshold_for_mode(Mode) -> - {Key, Fallback} = case Mode of - lazy -> {lazy_queue_explicit_gc_run_operation_threshold, - ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD}; - _ -> {queue_explicit_gc_run_operation_threshold, - ?DEFAULT_EXPLICIT_GC_RUN_OP_THRESHOLD} - end, - rabbit_misc:get_env(rabbit, Key, Fallback). - %%---------------------------------------------------------------------------- %% Public API %%---------------------------------------------------------------------------- @@ -597,27 +586,27 @@ publish(Msg, MsgProps, IsDelivered, ChPid, Flow, State) -> publish1(Msg, MsgProps, IsDelivered, ChPid, Flow, fun maybe_write_to_disk/4, State), - a(maybe_reduce_memory_use(maybe_update_rates(State1))). + a(reduce_memory_use(maybe_update_rates(State1))). batch_publish(Publishes, ChPid, Flow, State) -> {ChPid, Flow, State1} = lists:foldl(fun batch_publish1/2, {ChPid, Flow, State}, Publishes), State2 = ui(State1), - a(maybe_reduce_memory_use(maybe_update_rates(State2))). + a(reduce_memory_use(maybe_update_rates(State2))). publish_delivered(Msg, MsgProps, ChPid, Flow, State) -> {SeqId, State1} = publish_delivered1(Msg, MsgProps, ChPid, Flow, fun maybe_write_to_disk/4, State), - {SeqId, a(maybe_reduce_memory_use(maybe_update_rates(State1)))}. + {SeqId, a(reduce_memory_use(maybe_update_rates(State1)))}. batch_publish_delivered(Publishes, ChPid, Flow, State) -> {ChPid, Flow, SeqIds, State1} = lists:foldl(fun batch_publish_delivered1/2, {ChPid, Flow, [], State}, Publishes), State2 = ui(State1), - {lists:reverse(SeqIds), a(maybe_reduce_memory_use(maybe_update_rates(State2)))}. + {lists:reverse(SeqIds), a(reduce_memory_use(maybe_update_rates(State2)))}. discard(_MsgId, _ChPid, _Flow, State) -> State. @@ -721,7 +710,7 @@ requeue(AckTags, #vqstate { mode = default, {Delta1, MsgIds2, State3} = delta_merge(SeqIds1, Delta, MsgIds1, State2), MsgCount = length(MsgIds2), - {MsgIds2, a(maybe_reduce_memory_use( + {MsgIds2, a(reduce_memory_use( maybe_update_rates(ui( State3 #vqstate { delta = Delta1, q3 = Q3a, @@ -739,7 +728,7 @@ requeue(AckTags, #vqstate { mode = lazy, {Delta1, MsgIds1, State2} = delta_merge(SeqIds, Delta, MsgIds, State1), MsgCount = length(MsgIds1), - {MsgIds1, a(maybe_reduce_memory_use( + {MsgIds1, a(reduce_memory_use( maybe_update_rates(ui( State2 #vqstate { delta = Delta1, q3 = Q3a, @@ -789,7 +778,7 @@ set_ram_duration_target( (TargetRamCount =/= infinity andalso TargetRamCount1 >= TargetRamCount) of true -> State1; - false -> maybe_reduce_memory_use(State1) + false -> reduce_memory_use(State1) end). maybe_update_rates(State = #vqstate{ in_counter = InCount, @@ -871,7 +860,7 @@ timeout(State = #vqstate { index_state = IndexState }) -> handle_pre_hibernate(State = #vqstate { index_state = IndexState }) -> State #vqstate { index_state = rabbit_queue_index:flush(IndexState) }. -resume(State) -> a(maybe_reduce_memory_use(State)). +resume(State) -> a(reduce_memory_use(State)). msg_rates(#vqstate { rates = #rates { in = AvgIngressRate, out = AvgEgressRate } }) -> @@ -886,8 +875,6 @@ info(messages_ram, State) -> info(messages_ready_ram, State) + info(messages_unacknowledged_ram, State); info(messages_persistent, #vqstate{persistent_count = PersistentCount}) -> PersistentCount; -info(messages_paged_out, #vqstate{delta = #delta{transient = Count}}) -> - Count; info(message_bytes, #vqstate{bytes = Bytes, unacked_bytes = UBytes}) -> Bytes + UBytes; @@ -899,8 +886,6 @@ info(message_bytes_ram, #vqstate{ram_bytes = RamBytes}) -> RamBytes; info(message_bytes_persistent, #vqstate{persistent_bytes = PersistentBytes}) -> PersistentBytes; -info(message_bytes_paged_out, #vqstate{delta_transient_bytes = PagedOutBytes}) -> - PagedOutBytes; info(head_message_timestamp, #vqstate{ q3 = Q3, q4 = Q4, @@ -1257,14 +1242,14 @@ maybe_write_delivered(true, SeqId, IndexState) -> rabbit_queue_index:deliver([SeqId], IndexState). betas_from_index_entries(List, TransientThreshold, DelsAndAcksFun, State) -> - {Filtered, Delivers, Acks, RamReadyCount, RamBytes, TransientCount, TransientBytes} = + {Filtered, Delivers, Acks, RamReadyCount, RamBytes} = lists:foldr( fun ({_MsgOrId, SeqId, _MsgProps, IsPersistent, IsDelivered} = M, - {Filtered1, Delivers1, Acks1, RRC, RB, TC, TB} = Acc) -> + {Filtered1, Delivers1, Acks1, RRC, RB} = Acc) -> case SeqId < TransientThreshold andalso not IsPersistent of true -> {Filtered1, cons_if(not IsDelivered, SeqId, Delivers1), - [SeqId | Acks1], RRC, RB, TC, TB}; + [SeqId | Acks1], RRC, RB}; false -> MsgStatus = m(beta_msg_status(M)), HaveMsg = msg_in_ram(MsgStatus), Size = msg_size(MsgStatus), @@ -1272,15 +1257,12 @@ betas_from_index_entries(List, TransientThreshold, DelsAndAcksFun, State) -> false -> {?QUEUE:in_r(MsgStatus, Filtered1), Delivers1, Acks1, RRC + one_if(HaveMsg), - RB + one_if(HaveMsg) * Size, - TC + one_if(not IsPersistent), - TB + one_if(not IsPersistent) * Size}; + RB + one_if(HaveMsg) * Size}; true -> Acc %% [0] end end - end, {?QUEUE:new(), [], [], 0, 0, 0, 0}, List), - {Filtered, RamReadyCount, RamBytes, DelsAndAcksFun(Delivers, Acks, State), - TransientCount, TransientBytes}. + end, {?QUEUE:new(), [], [], 0, 0}, List), + {Filtered, RamReadyCount, RamBytes, DelsAndAcksFun(Delivers, Acks, State)}. %% [0] We don't increase RamBytes here, even though it pertains to %% unacked messages too, since if HaveMsg then the message must have %% been stored in the QI, thus the message must have been in @@ -1293,28 +1275,18 @@ is_msg_in_pending_acks(SeqId, #vqstate { ram_pending_ack = RPA, gb_trees:is_defined(SeqId, DPA) orelse gb_trees:is_defined(SeqId, QPA)). -expand_delta(SeqId, ?BLANK_DELTA_PATTERN(X), IsPersistent) -> - d(#delta { start_seq_id = SeqId, count = 1, end_seq_id = SeqId + 1, - transient = one_if(not IsPersistent)}); +expand_delta(SeqId, ?BLANK_DELTA_PATTERN(X)) -> + d(#delta { start_seq_id = SeqId, count = 1, end_seq_id = SeqId + 1 }); expand_delta(SeqId, #delta { start_seq_id = StartSeqId, - count = Count, - transient = Transient } = Delta, - IsPersistent ) + count = Count } = Delta) when SeqId < StartSeqId -> - d(Delta #delta { start_seq_id = SeqId, count = Count + 1, - transient = Transient + one_if(not IsPersistent)}); + d(Delta #delta { start_seq_id = SeqId, count = Count + 1 }); expand_delta(SeqId, #delta { count = Count, - end_seq_id = EndSeqId, - transient = Transient } = Delta, - IsPersistent) + end_seq_id = EndSeqId } = Delta) when SeqId >= EndSeqId -> - d(Delta #delta { count = Count + 1, end_seq_id = SeqId + 1, - transient = Transient + one_if(not IsPersistent)}); -expand_delta(_SeqId, #delta { count = Count, - transient = Transient } = Delta, - IsPersistent ) -> - d(Delta #delta { count = Count + 1, - transient = Transient + one_if(not IsPersistent) }). + d(Delta #delta { count = Count + 1, end_seq_id = SeqId + 1 }); +expand_delta(_SeqId, #delta { count = Count } = Delta) -> + d(Delta #delta { count = Count + 1 }). %%---------------------------------------------------------------------------- %% Internal major helpers for Public API @@ -1336,7 +1308,6 @@ init(IsDurable, IndexState, DeltaCount, DeltaBytes, Terms, true -> ?BLANK_DELTA; false -> d(#delta { start_seq_id = LowSeqId, count = DeltaCount1, - transient = 0, end_seq_id = NextSeqId }) end, Now = time_compat:monotonic_time(), @@ -1365,7 +1336,6 @@ init(IsDurable, IndexState, DeltaCount, DeltaBytes, Terms, persistent_count = DeltaCount1, bytes = DeltaBytes1, persistent_bytes = DeltaBytes1, - delta_transient_bytes = 0, target_ram_count = infinity, ram_msg_count = 0, @@ -1405,22 +1375,22 @@ in_r(MsgStatus = #msg_status { msg = undefined }, false -> {Msg, State1 = #vqstate { q4 = Q4a }} = read_msg(MsgStatus, State), MsgStatus1 = MsgStatus#msg_status{msg = Msg}, - stats(ready0, {MsgStatus, MsgStatus1}, 0, + stats(ready0, {MsgStatus, MsgStatus1}, State1 #vqstate { q4 = ?QUEUE:in_r(MsgStatus1, Q4a) }) end; in_r(MsgStatus, State = #vqstate { mode = default, q4 = Q4 }) -> State #vqstate { q4 = ?QUEUE:in_r(MsgStatus, Q4) }; %% lazy queues -in_r(MsgStatus = #msg_status { seq_id = SeqId, is_persistent = IsPersistent }, +in_r(MsgStatus = #msg_status { seq_id = SeqId }, State = #vqstate { mode = lazy, q3 = Q3, delta = Delta}) -> case ?QUEUE:is_empty(Q3) of true -> {_MsgStatus1, State1} = maybe_write_to_disk(true, true, MsgStatus, State), - State2 = stats(ready0, {MsgStatus, none}, 1, State1), - Delta1 = expand_delta(SeqId, Delta, IsPersistent), - State2 #vqstate{ delta = Delta1}; + State2 = stats(ready0, {MsgStatus, none}, State1), + Delta1 = expand_delta(SeqId, Delta), + State2 #vqstate{ delta = Delta1 }; false -> State #vqstate { q3 = ?QUEUE:in_r(MsgStatus, Q3) } end. @@ -1456,8 +1426,8 @@ read_msg(MsgId, IsPersistent, State = #vqstate{msg_store_clients = MSCState, {Msg, State #vqstate {msg_store_clients = MSCState1, disk_read_count = Count + 1}}. -stats(Signs, Statuses, DeltaPaged, State) -> - stats0(expand_signs(Signs), expand_statuses(Statuses), DeltaPaged, State). +stats(Signs, Statuses, State) -> + stats0(expand_signs(Signs), expand_statuses(Statuses), State). expand_signs(ready0) -> {0, 0, true}; expand_signs(lazy_pub) -> {1, 0, true}; @@ -1472,14 +1442,13 @@ expand_statuses({B, A}) -> {msg_in_ram(B), msg_in_ram(A), B}. %% contains "Ready" or "Unacked" iff that is what it counts. If %% neither is present it counts both. stats0({DeltaReady, DeltaUnacked, ReadyMsgPaged}, - {InRamBefore, InRamAfter, MsgStatus}, DeltaPaged, + {InRamBefore, InRamAfter, MsgStatus}, State = #vqstate{len = ReadyCount, bytes = ReadyBytes, ram_msg_count = RamReadyCount, persistent_count = PersistentCount, unacked_bytes = UnackedBytes, ram_bytes = RamBytes, - delta_transient_bytes = DeltaBytes, persistent_bytes = PersistentBytes}) -> S = msg_size(MsgStatus), DeltaTotal = DeltaReady + DeltaUnacked, @@ -1502,8 +1471,7 @@ stats0({DeltaReady, DeltaUnacked, ReadyMsgPaged}, bytes = ReadyBytes + DeltaReady * S, unacked_bytes = UnackedBytes + DeltaUnacked * S, ram_bytes = RamBytes + DeltaRam * S, - persistent_bytes = PersistentBytes + DeltaPersistent * S, - delta_transient_bytes = DeltaBytes + DeltaPaged * one_if(not MsgStatus#msg_status.is_persistent) * S}. + persistent_bytes = PersistentBytes + DeltaPersistent * S}. msg_size(#msg_status{msg_props = #message_properties{size = Size}}) -> Size. @@ -1525,7 +1493,7 @@ remove(true, MsgStatus = #msg_status { MsgStatus #msg_status { is_delivered = true }, State), - State2 = stats({-1, 1}, {MsgStatus, MsgStatus}, 0, State1), + State2 = stats({-1, 1}, {MsgStatus, MsgStatus}, State1), {SeqId, maybe_update_rates( State2 #vqstate {out_counter = OutCount + 1, @@ -1561,7 +1529,7 @@ remove(false, MsgStatus = #msg_status { false -> IndexState1 end, - State1 = stats({-1, 0}, {MsgStatus, none}, 0, State), + State1 = stats({-1, 0}, {MsgStatus, none}, State), {undefined, maybe_update_rates( State1 #vqstate {out_counter = OutCount + 1, @@ -1645,7 +1613,7 @@ process_queue_entries1( is_delivered = true }, State1), {cons_if(IndexOnDisk andalso not IsDelivered, SeqId, Delivers), Fun(Msg, SeqId, FetchAcc), - stats({-1, 1}, {MsgStatus, MsgStatus}, 0, State2)}. + stats({-1, 1}, {MsgStatus, MsgStatus}, State2)}. collect_by_predicate(Pred, QAcc, State) -> case queue_out(State) of @@ -1747,7 +1715,7 @@ remove_queue_entries1( end, cons_if(IndexOnDisk andalso not IsDelivered, SeqId, Delivers), cons_if(IndexOnDisk, SeqId, Acks), - stats({-1, 0}, {MsgStatus, none}, 0, State)}. + stats({-1, 0}, {MsgStatus, none}, State)}. process_delivers_and_acks_fun(deliver_and_ack) -> fun (Delivers, Acks, State = #vqstate { index_state = IndexState }) -> @@ -1784,7 +1752,7 @@ publish1(Msg = #basic_message { is_persistent = IsPersistent, id = MsgId }, end, InCount1 = InCount + 1, UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC), - stats({1, 0}, {none, MsgStatus1}, 0, + stats({1, 0}, {none, MsgStatus1}, State2#vqstate{ next_seq_id = SeqId + 1, in_counter = InCount1, unconfirmed = UC1 }); @@ -1797,17 +1765,17 @@ publish1(Msg = #basic_message { is_persistent = IsPersistent, id = MsgId }, in_counter = InCount, durable = IsDurable, unconfirmed = UC, - delta = Delta}) -> + delta = Delta }) -> IsPersistent1 = IsDurable andalso IsPersistent, MsgStatus = msg_status(IsPersistent1, IsDelivered, SeqId, Msg, MsgProps, IndexMaxSize), {MsgStatus1, State1} = PersistFun(true, true, MsgStatus, State), - Delta1 = expand_delta(SeqId, Delta, IsPersistent), + Delta1 = expand_delta(SeqId, Delta), UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC), - stats(lazy_pub, {lazy, m(MsgStatus1)}, 1, + stats(lazy_pub, {lazy, m(MsgStatus1)}, State1#vqstate{ delta = Delta1, next_seq_id = SeqId + 1, in_counter = InCount + 1, - unconfirmed = UC1}). + unconfirmed = UC1 }). batch_publish1({Msg, MsgProps, IsDelivered}, {ChPid, Flow, State}) -> {ChPid, Flow, publish1(Msg, MsgProps, IsDelivered, ChPid, Flow, @@ -1830,7 +1798,7 @@ publish_delivered1(Msg = #basic_message { is_persistent = IsPersistent, {MsgStatus1, State1} = PersistFun(false, false, MsgStatus, State), State2 = record_pending_ack(m(MsgStatus1), State1), UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC), - State3 = stats({0, 1}, {none, MsgStatus1}, 0, + State3 = stats({0, 1}, {none, MsgStatus1}, State2 #vqstate { next_seq_id = SeqId + 1, out_counter = OutCount + 1, in_counter = InCount + 1, @@ -1853,7 +1821,7 @@ publish_delivered1(Msg = #basic_message { is_persistent = IsPersistent, {MsgStatus1, State1} = PersistFun(true, true, MsgStatus, State), State2 = record_pending_ack(m(MsgStatus1), State1), UC1 = gb_sets_maybe_insert(NeedsConfirming, MsgId, UC), - State3 = stats({0, 1}, {none, MsgStatus1}, 0, + State3 = stats({0, 1}, {none, MsgStatus1}, State2 #vqstate { next_seq_id = SeqId + 1, out_counter = OutCount + 1, in_counter = InCount + 1, @@ -2041,7 +2009,7 @@ remove_pending_ack(true, SeqId, State) -> {none, _} -> {none, State}; {MsgStatus, State1} -> - {MsgStatus, stats({0, -1}, {MsgStatus, none}, 0, State1)} + {MsgStatus, stats({0, -1}, {MsgStatus, none}, State1)} end; remove_pending_ack(false, SeqId, State = #vqstate{ram_pending_ack = RPA, disk_pending_ack = DPA, @@ -2186,14 +2154,14 @@ msgs_and_indices_written_to_disk(Callback, MsgIdSet) -> publish_alpha(#msg_status { msg = undefined } = MsgStatus, State) -> {Msg, State1} = read_msg(MsgStatus, State), MsgStatus1 = MsgStatus#msg_status { msg = Msg }, - {MsgStatus1, stats({1, -1}, {MsgStatus, MsgStatus1}, 0, State1)}; + {MsgStatus1, stats({1, -1}, {MsgStatus, MsgStatus1}, State1)}; publish_alpha(MsgStatus, State) -> - {MsgStatus, stats({1, -1}, {MsgStatus, MsgStatus}, 0, State)}. + {MsgStatus, stats({1, -1}, {MsgStatus, MsgStatus}, State)}. publish_beta(MsgStatus, State) -> {MsgStatus1, State1} = maybe_prepare_write_to_disk(true, false, MsgStatus, State), MsgStatus2 = m(trim_msg_status(MsgStatus1)), - {MsgStatus2, stats({1, -1}, {MsgStatus, MsgStatus2}, 0, State1)}. + {MsgStatus2, stats({1, -1}, {MsgStatus, MsgStatus2}, State1)}. %% Rebuild queue, inserting sequence ids to maintain ordering queue_merge(SeqIds, Q, MsgIds, Limit, PubFun, State) -> @@ -2232,12 +2200,11 @@ delta_merge(SeqIds, Delta, MsgIds, State) -> case msg_from_pending_ack(SeqId, State0) of {none, _} -> Acc; - {#msg_status { msg_id = MsgId, - is_persistent = IsPersistent } = MsgStatus, State1} -> + {#msg_status { msg_id = MsgId } = MsgStatus, State1} -> {_MsgStatus, State2} = maybe_prepare_write_to_disk(true, true, MsgStatus, State1), - {expand_delta(SeqId, Delta0, IsPersistent), [MsgId | MsgIds0], - stats({1, -1}, {MsgStatus, none}, 1, State2)} + {expand_delta(SeqId, Delta0), [MsgId | MsgIds0], + stats({1, -1}, {MsgStatus, none}, State2)} end end, {Delta, MsgIds, State}, SeqIds). @@ -2343,12 +2310,12 @@ ifold(Fun, Acc, Its, State) -> %% Phase changes %%---------------------------------------------------------------------------- -maybe_reduce_memory_use(State = #vqstate {memory_reduction_run_count = MRedRunCount, - mode = Mode}) -> - case MRedRunCount >= ?EXPLICIT_GC_RUN_OP_THRESHOLD(Mode) of - true -> State1 = reduce_memory_use(State), - State1#vqstate{memory_reduction_run_count = 0}; - false -> State#vqstate{memory_reduction_run_count = MRedRunCount + 1} +maybe_execute_gc(State = #vqstate {memory_reduction_run_count = MRedRunCount}) -> + case MRedRunCount >= ?EXPLICIT_GC_RUN_OP_THRESHOLD of + true -> garbage_collect(), + State#vqstate{memory_reduction_run_count = 0}; + false -> State#vqstate{memory_reduction_run_count = MRedRunCount + 1} + end. reduce_memory_use(State = #vqstate { target_ram_count = infinity }) -> @@ -2363,6 +2330,7 @@ reduce_memory_use(State = #vqstate { out = AvgEgress, ack_in = AvgAckIngress, ack_out = AvgAckEgress } }) -> + State1 = #vqstate { q2 = Q2, q3 = Q3 } = case chunk_size(RamMsgCount + gb_trees:size(RPA), TargetRamCount) of 0 -> State; @@ -2422,8 +2390,7 @@ reduce_memory_use(State = #vqstate { S2 -> push_betas_to_deltas(S2, State1) end, - garbage_collect(), - State3. + maybe_execute_gc(State3). limit_ram_acks(0, State) -> {0, ui(State)}; @@ -2439,7 +2406,7 @@ limit_ram_acks(Quota, State = #vqstate { ram_pending_ack = RPA, MsgStatus2 = m(trim_msg_status(MsgStatus1)), DPA1 = gb_trees:insert(SeqId, MsgStatus2, DPA), limit_ram_acks(Quota - 1, - stats({0, 0}, {MsgStatus, MsgStatus2}, 0, + stats({0, 0}, {MsgStatus, MsgStatus2}, State1 #vqstate { ram_pending_ack = RPA1, disk_pending_ack = DPA1 })) end. @@ -2528,18 +2495,16 @@ maybe_deltas_to_betas(DelsAndAcksFun, ram_msg_count = RamMsgCount, ram_bytes = RamBytes, disk_read_count = DiskReadCount, - delta_transient_bytes = DeltaTransientBytes, transient_threshold = TransientThreshold }) -> #delta { start_seq_id = DeltaSeqId, count = DeltaCount, - transient = Transient, end_seq_id = DeltaSeqIdEnd } = Delta, DeltaSeqId1 = lists:min([rabbit_queue_index:next_segment_boundary(DeltaSeqId), DeltaSeqIdEnd]), {List, IndexState1} = rabbit_queue_index:read(DeltaSeqId, DeltaSeqId1, IndexState), - {Q3a, RamCountsInc, RamBytesInc, State1, TransientCount, TransientBytes} = + {Q3a, RamCountsInc, RamBytesInc, State1} = betas_from_index_entries(List, TransientThreshold, DelsAndAcksFun, State #vqstate { index_state = IndexState1 }), @@ -2562,16 +2527,13 @@ maybe_deltas_to_betas(DelsAndAcksFun, %% can now join q2 onto q3 State2 #vqstate { q2 = ?QUEUE:new(), delta = ?BLANK_DELTA, - q3 = ?QUEUE:join(Q3b, Q2), - delta_transient_bytes = 0}; + q3 = ?QUEUE:join(Q3b, Q2) }; N when N > 0 -> Delta1 = d(#delta { start_seq_id = DeltaSeqId1, count = N, - transient = Transient - TransientCount, end_seq_id = DeltaSeqIdEnd }), State2 #vqstate { delta = Delta1, - q3 = Q3b, - delta_transient_bytes = DeltaTransientBytes - TransientBytes } + q3 = Q3b } end end. @@ -2580,8 +2542,7 @@ push_alphas_to_betas(Quota, State) -> push_alphas_to_betas( fun ?QUEUE:out/1, fun (MsgStatus, Q1a, - State0 = #vqstate { q3 = Q3, delta = #delta { count = 0, - transient = 0 } }) -> + State0 = #vqstate { q3 = Q3, delta = #delta { count = 0 } }) -> State0 #vqstate { q1 = Q1a, q3 = ?QUEUE:in(MsgStatus, Q3) }; (MsgStatus, Q1a, State0 = #vqstate { q2 = Q2 }) -> State0 #vqstate { q1 = Q1a, q2 = ?QUEUE:in(MsgStatus, Q2) } @@ -2617,7 +2578,7 @@ push_alphas_to_betas(Generator, Consumer, Quota, Q, State) -> State), MsgStatus2 = m(trim_msg_status(MsgStatus1)), State2 = stats( - ready0, {MsgStatus, MsgStatus2}, 0, State1), + ready0, {MsgStatus, MsgStatus2}, State1), State3 = Consumer(MsgStatus2, Qa, State2), push_alphas_to_betas(Generator, Consumer, Quota - 1, Qa, State3) @@ -2680,11 +2641,10 @@ push_betas_to_deltas1(Generator, Limit, Q, {Quota, Delta, State}) -> when SeqId < Limit -> {Q, {Quota, Delta, ui(State)}}; {{value, MsgStatus = #msg_status { seq_id = SeqId }}, Qa} -> - {#msg_status { index_on_disk = true, - is_persistent = IsPersistent }, State1} = + {#msg_status { index_on_disk = true }, State1} = maybe_batch_write_index_to_disk(true, MsgStatus, State), - State2 = stats(ready0, {MsgStatus, none}, 1, State1), - Delta1 = expand_delta(SeqId, Delta, IsPersistent), + State2 = stats(ready0, {MsgStatus, none}, State1), + Delta1 = expand_delta(SeqId, Delta), push_betas_to_deltas1(Generator, Limit, Qa, {Quota - 1, Delta1, State2}) end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_version.erl b/deps/rabbit/src/rabbit_version.erl similarity index 99% rename from rabbitmq-server/deps/rabbit/src/rabbit_version.erl rename to deps/rabbit/src/rabbit_version.erl index 020ed59..a27f0ac 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_version.erl +++ b/deps/rabbit/src/rabbit_version.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_version). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_vhost.erl b/deps/rabbit/src/rabbit_vhost.erl similarity index 94% rename from rabbitmq-server/deps/rabbit/src/rabbit_vhost.erl rename to deps/rabbit/src/rabbit_vhost.erl index b557bb2..df2f842 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_vhost.erl +++ b/deps/rabbit/src/rabbit_vhost.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_vhost). @@ -20,7 +20,7 @@ %%---------------------------------------------------------------------------- --export([add/1, delete/1, exists/1, list/0, with/2, with_user_and_vhost/3, assert/1]). +-export([add/1, delete/1, exists/1, list/0, with/2, assert/1]). -export([info/1, info/2, info_all/0, info_all/1, info_all/2, info_all/3]). -spec add(rabbit_types:vhost()) -> 'ok'. @@ -28,8 +28,6 @@ -spec exists(rabbit_types:vhost()) -> boolean(). -spec list() -> [rabbit_types:vhost()]. -spec with(rabbit_types:vhost(), rabbit_misc:thunk(A)) -> A. --spec with_user_and_vhost - (rabbit_types:username(), rabbit_types:vhost(), rabbit_misc:thunk(A)) -> A. -spec assert(rabbit_types:vhost()) -> 'ok'. -spec info(rabbit_types:vhost()) -> rabbit_types:infos(). @@ -134,9 +132,6 @@ with(VHostPath, Thunk) -> end end. -with_user_and_vhost(Username, VHostPath, Thunk) -> - rabbit_misc:with_user(Username, with(VHostPath, Thunk)). - %% Like with/2 but outside an Mnesia tx assert(VHostPath) -> case exists(VHostPath) of true -> ok; diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_vm.erl b/deps/rabbit/src/rabbit_vm.erl similarity index 89% rename from rabbitmq-server/deps/rabbit/src/rabbit_vm.erl rename to deps/rabbit/src/rabbit_vm.erl index 685cea2..9c8732b 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_vm.erl +++ b/deps/rabbit/src/rabbit_vm.erl @@ -11,14 +11,15 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_vm). -export([memory/0, binary/0, ets_tables_memory/1]). --define(MAGIC_PLUGINS, ["cowboy", "sockjs", "rfc4627_jsonrpc"]). +-define(MAGIC_PLUGINS, ["mochiweb", "webmachine", "cowboy", "sockjs", + "rfc4627_jsonrpc"]). %%---------------------------------------------------------------------------- @@ -30,6 +31,7 @@ %%---------------------------------------------------------------------------- +%% Like erlang:memory(), but with awareness of rabbit-y things memory() -> All = interesting_sups(), {Sums, _Other} = sum_processes( @@ -40,21 +42,11 @@ memory() -> [aggregate(Names, Sums, memory, fun (X) -> X end) || Names <- distinguished_interesting_sups()], - MnesiaETS = mnesia_memory(), - MsgIndexETS = ets_memory([msg_store_persistent, msg_store_transient]), - MetricsETS = ets_memory([rabbit_metrics]), - MetricsProc = try - [{_, M}] = process_info(whereis(rabbit_metrics), [memory]), - M - catch - error:badarg -> - 0 - end, - MgmtDbETS = ets_memory([rabbit_mgmt_storage]), - VMTotal = vm_memory_monitor:get_process_memory(), - - - [{total, ErlangTotal}, + Mnesia = mnesia_memory(), + MsgIndexETS = ets_memory([msg_store_persistent, msg_store_transient]), + MgmtDbETS = ets_memory([rabbit_mgmt_event_collector]), + + [{total, Total}, {processes, Processes}, {ets, ETS}, {atom, Atom}, @@ -63,49 +55,28 @@ memory() -> {system, System}] = erlang:memory([total, processes, ets, atom, binary, code, system]), - Unaccounted = case VMTotal - ErlangTotal of - GTZ when GTZ > 0 -> GTZ; - _LTZ -> 0 - end, - OtherProc = Processes - ConnsReader - ConnsWriter - ConnsChannel - ConnsOther - - Qs - QsSlave - MsgIndexProc - Plugins - MgmtDbProc - MetricsProc, + - Qs - QsSlave - MsgIndexProc - Plugins - MgmtDbProc, - [ - %% Connections + [{total, Total}, {connection_readers, ConnsReader}, {connection_writers, ConnsWriter}, {connection_channels, ConnsChannel}, {connection_other, ConnsOther}, - - %% Queues {queue_procs, Qs}, {queue_slave_procs, QsSlave}, - - %% Processes {plugins, Plugins}, {other_proc, lists:max([0, OtherProc])}, %% [1] - - %% Metrics - {metrics, MetricsETS + MetricsProc}, + {mnesia, Mnesia}, {mgmt_db, MgmtDbETS + MgmtDbProc}, - - %% ETS - {mnesia, MnesiaETS}, - {other_ets, ETS - MnesiaETS - MetricsETS - MgmtDbETS - MsgIndexETS}, - - %% Messages (mostly, some binaries are not messages) - {binary, Bin}, {msg_index, MsgIndexETS + MsgIndexProc}, - - %% System + {other_ets, ETS - Mnesia - MsgIndexETS - MgmtDbETS}, + {binary, Bin}, {code, Code}, {atom, Atom}, - {other_system, System - ETS - Bin - Code - Atom + Unaccounted}, + {other_system, System - ETS - Atom - Bin - Code}]. - {total, VMTotal} - ]. %% [1] - erlang:memory(processes) can be less than the sum of its %% parts. Rather than display something nonsensical, just silence any %% claims about negative memory. See diff --git a/rabbitmq-server/deps/rabbit/src/supervised_lifecycle.erl b/deps/rabbit/src/supervised_lifecycle.erl similarity index 96% rename from rabbitmq-server/deps/rabbit/src/supervised_lifecycle.erl rename to deps/rabbit/src/supervised_lifecycle.erl index 3e1918d..5b0f56d 100644 --- a/rabbitmq-server/deps/rabbit/src/supervised_lifecycle.erl +++ b/deps/rabbit/src/supervised_lifecycle.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% Invoke callbacks on startup and termination. diff --git a/rabbitmq-server/deps/rabbit/src/tcp_listener.erl b/deps/rabbit/src/tcp_listener.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/tcp_listener.erl rename to deps/rabbit/src/tcp_listener.erl index 7c2f4a4..5f15592 100644 --- a/rabbitmq-server/deps/rabbit/src/tcp_listener.erl +++ b/deps/rabbit/src/tcp_listener.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(tcp_listener). diff --git a/rabbitmq-server/deps/rabbit/src/tcp_listener_sup.erl b/deps/rabbit/src/tcp_listener_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/tcp_listener_sup.erl rename to deps/rabbit/src/tcp_listener_sup.erl index 1465453..5ef652a 100644 --- a/rabbitmq-server/deps/rabbit/src/tcp_listener_sup.erl +++ b/deps/rabbit/src/tcp_listener_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(tcp_listener_sup). diff --git a/rabbitmq-server/deps/rabbit/src/truncate.erl b/deps/rabbit/src/truncate.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/truncate.erl rename to deps/rabbit/src/truncate.erl index 034bc62..a1586b0 100644 --- a/rabbitmq-server/deps/rabbit/src/truncate.erl +++ b/deps/rabbit/src/truncate.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(truncate). diff --git a/rabbitmq-server/deps/rabbit_common/src/vm_memory_monitor.erl b/deps/rabbit/src/vm_memory_monitor.erl similarity index 67% rename from rabbitmq-server/deps/rabbit_common/src/vm_memory_monitor.erl rename to deps/rabbit/src/vm_memory_monitor.erl index 50232da..6b04368 100644 --- a/rabbitmq-server/deps/rabbit_common/src/vm_memory_monitor.erl +++ b/deps/rabbit/src/vm_memory_monitor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% In practice Erlang shouldn't be allowed to grow to more than a half @@ -35,13 +35,21 @@ -export([get_total_memory/0, get_vm_limit/0, get_check_interval/0, set_check_interval/1, get_vm_memory_high_watermark/0, set_vm_memory_high_watermark/1, - get_memory_limit/0, get_memory_use/1, - get_process_memory/0, get_memory_calculation_strategy/0]). + get_memory_limit/0]). %% for tests --export([parse_line_linux/1, parse_mem_limit/1]). +-export([parse_line_linux/1]). + -define(SERVER, ?MODULE). +-define(DEFAULT_MEMORY_CHECK_INTERVAL, 1000). +-define(ONE_MB, 1048576). + +%% For an unknown OS, we assume that we have 1GB of memory. It'll be +%% wrong. Scale by vm_memory_high_watermark in configuration to get a +%% sensible value. +-define(MEMORY_SIZE_FOR_UNKNOWN_OS, 1073741824). +-define(DEFAULT_VM_MEMORY_HIGH_WATERMARK, 0.4). -record(state, {total_memory, memory_limit, @@ -52,8 +60,6 @@ alarm_funs }). --include("rabbit_memory.hrl"). - %%---------------------------------------------------------------------------- -type vm_memory_high_watermark() :: (float() | {'absolute', integer() | string()}). @@ -67,28 +73,19 @@ -spec get_vm_memory_high_watermark() -> vm_memory_high_watermark(). -spec set_vm_memory_high_watermark(vm_memory_high_watermark()) -> 'ok'. -spec get_memory_limit() -> non_neg_integer(). --spec get_memory_use(bytes) -> {non_neg_integer(), float() | infinity}; - (ratio) -> float() | infinity. %%---------------------------------------------------------------------------- %% Public API %%---------------------------------------------------------------------------- get_total_memory() -> - case application:get_env(rabbit, total_memory_available_override_value) of - {ok, Value} -> - case rabbit_resource_monitor_misc:parse_information_unit(Value) of - {ok, ParsedTotal} -> - ParsedTotal; - {error, parse_error} -> - rabbit_log:warning( - "The override value for the total memmory available is " - "not a valid value: ~p, getting total from the system.~n", - [Value]), - get_total_memory_from_os() - end; - undefined -> - get_total_memory_from_os() + try + get_total_memory(os:type()) + catch _:Error -> + rabbit_log:warning( + "Failed to get total system memory: ~n~p~n~p~n", + [Error, erlang:get_stacktrace()]), + unknown end. get_vm_limit() -> get_vm_limit(os:type()). @@ -109,109 +106,6 @@ set_vm_memory_high_watermark(Fraction) -> get_memory_limit() -> gen_server:call(?MODULE, get_memory_limit, infinity). -get_memory_use(bytes) -> - MemoryLimit = get_memory_limit(), - {get_process_memory(), case MemoryLimit > 0.0 of - true -> MemoryLimit; - false -> infinity - end}; -get_memory_use(ratio) -> - MemoryLimit = get_memory_limit(), - case MemoryLimit > 0.0 of - true -> get_process_memory() / MemoryLimit; - false -> infinity - end. - -%% Memory reported by erlang:memory(total) is not supposed to -%% be equal to the total size of all pages mapped to the emulator, -%% according to http://erlang.org/doc/man/erlang.html#memory-0 -%% erlang:memory(total) under-reports memory usage by around 20% --spec get_process_memory() -> Bytes :: integer(). -get_process_memory() -> - case get_memory_calculation_strategy() of - rss -> - case get_system_process_resident_memory() of - {ok, MemInBytes} -> - MemInBytes; - {error, Reason} -> - rabbit_log:debug("Unable to get system memory used. Reason: ~p." - " Falling back to erlang memory reporting", - [Reason]), - erlang:memory(total) - end; - erlang -> - erlang:memory(total) - end. - --spec get_memory_calculation_strategy() -> rss | erlang. -get_memory_calculation_strategy() -> - case rabbit_misc:get_env(rabbit, vm_memory_calculation_strategy, rss) of - erlang -> - erlang; - rss -> - rss; - UnsupportedValue -> - rabbit_log:warning( - "Unsupported value '~p' for vm_memory_calculation_strategy. " - "Supported values: (rss|erlang). " - "Defaulting to 'rss'", - [UnsupportedValue] - ), - rss - end. - --spec get_system_process_resident_memory() -> {ok, Bytes :: integer()} | {error, term()}. -get_system_process_resident_memory() -> - try - get_system_process_resident_memory(os:type()) - catch _:Error -> - {error, {"Failed to get process resident memory", Error}} - end. - -get_system_process_resident_memory({unix,darwin}) -> - get_ps_memory(); - -get_system_process_resident_memory({unix, linux}) -> - get_ps_memory(); - -get_system_process_resident_memory({unix,freebsd}) -> - get_ps_memory(); - -get_system_process_resident_memory({unix,openbsd}) -> - get_ps_memory(); - -get_system_process_resident_memory({win32,_OSname}) -> - OsPid = os:getpid(), - Cmd = "wmic process where processid=" ++ OsPid ++ " get WorkingSetSize /value 2>&1", - CmdOutput = os:cmd(Cmd), - %% Memory usage is displayed in bytes - case re:run(CmdOutput, "WorkingSetSize=([0-9]+)", [{capture, all_but_first, binary}]) of - {match, [Match]} -> - {ok, binary_to_integer(Match)}; - _ -> - {error, {unexpected_output_from_command, Cmd, CmdOutput}} - end; - -get_system_process_resident_memory({unix, sunos}) -> - get_ps_memory(); - -get_system_process_resident_memory({unix, aix}) -> - get_ps_memory(); - -get_system_process_resident_memory(_OsType) -> - {error, not_implemented_for_os}. - -get_ps_memory() -> - OsPid = os:getpid(), - Cmd = "ps -p " ++ OsPid ++ " -o rss=", - CmdOutput = os:cmd(Cmd), - case re:run(CmdOutput, "[0-9]+", [{capture, first, list}]) of - {match, [Match]} -> - {ok, list_to_integer(Match) * 1024}; - _ -> - {error, {unexpected_output_from_command, Cmd, CmdOutput}} - end. - %%---------------------------------------------------------------------------- %% gen_server callbacks %%---------------------------------------------------------------------------- @@ -233,7 +127,7 @@ init([MemFraction, AlarmFuns]) -> {ok, set_mem_limits(State, MemFraction)}. handle_call(get_vm_memory_high_watermark, _From, - #state{memory_config_limit = MemLimit} = State) -> + #state{memory_config_limit = MemLimit} = State) -> {reply, MemLimit, State}; handle_call({set_vm_memory_high_watermark, MemLimit}, _From, State) -> @@ -270,20 +164,11 @@ code_change(_OldVsn, State, _Extra) -> %%---------------------------------------------------------------------------- %% Server Internals %%---------------------------------------------------------------------------- -get_total_memory_from_os() -> - try - get_total_memory(os:type()) - catch _:Error -> - rabbit_log:warning( - "Failed to get total system memory: ~n~p~n~p~n", - [Error, erlang:get_stacktrace()]), - unknown - end. set_mem_limits(State, MemLimit) -> case erlang:system_info(wordsize) of 4 -> - rabbit_log:warning( + error_logger:warning_msg( "You are using a 32-bit version of Erlang: you may run into " "memory address~n" "space exhaustion or statistic counters overflow.~n"); @@ -296,39 +181,33 @@ set_mem_limits(State, MemLimit) -> case State of #state { total_memory = undefined, memory_limit = undefined } -> - rabbit_log:warning( + error_logger:warning_msg( "Unknown total memory size for your OS ~p. " - "Assuming memory size is ~p MiB (~p bytes).~n", + "Assuming memory size is ~pMB.~n", [os:type(), - trunc(?MEMORY_SIZE_FOR_UNKNOWN_OS/?ONE_MiB), - ?MEMORY_SIZE_FOR_UNKNOWN_OS]); + trunc(?MEMORY_SIZE_FOR_UNKNOWN_OS/?ONE_MB)]); _ -> ok end, ?MEMORY_SIZE_FOR_UNKNOWN_OS; - Memory -> Memory + M -> M end, UsableMemory = case get_vm_limit() of Limit when Limit < TotalMemory -> - rabbit_log:warning( - "Only ~p MiB (~p bytes) of ~p MiB (~p bytes) memory usable due to " + error_logger:warning_msg( + "Only ~pMB of ~pMB memory usable due to " "limited address space.~n" "Crashes due to memory exhaustion are possible - see~n" "http://www.rabbitmq.com/memory.html#address-space~n", - [trunc(Limit/?ONE_MiB), Limit, trunc(TotalMemory/?ONE_MiB), - TotalMemory]), + [trunc(V/?ONE_MB) || V <- [Limit, TotalMemory]]), Limit; _ -> TotalMemory end, MemLim = interpret_limit(parse_mem_limit(MemLimit), UsableMemory), - rabbit_log:info( - "Memory high watermark set to ~p MiB (~p bytes)" - " of ~p MiB (~p bytes) total~n", - [trunc(MemLim/?ONE_MiB), MemLim, - trunc(TotalMemory/?ONE_MiB), TotalMemory] - ), + error_logger:info_msg("Memory limit set to ~pMB of ~pMB total.~n", + [trunc(MemLim/?ONE_MB), trunc(TotalMemory/?ONE_MB)]), internal_update(State #state { total_memory = TotalMemory, memory_limit = MemLim, memory_config_limit = MemLimit}). @@ -338,6 +217,7 @@ interpret_limit({'absolute', MemLim}, UsableMemory) -> interpret_limit(MemFraction, UsableMemory) -> trunc(MemFraction * UsableMemory). + parse_mem_limit({absolute, Limit}) -> case rabbit_resource_monitor_misc:parse_information_unit(Limit) of {ok, ParsedLimit} -> {absolute, ParsedLimit}; @@ -345,27 +225,16 @@ parse_mem_limit({absolute, Limit}) -> rabbit_log:error("Unable to parse vm_memory_high_watermark value ~p", [Limit]), ?DEFAULT_VM_MEMORY_HIGH_WATERMARK end; -parse_mem_limit(MemLimit) when is_integer(MemLimit) -> - parse_mem_limit(float(MemLimit)); -parse_mem_limit(MemLimit) when is_float(MemLimit), MemLimit =< ?MAX_VM_MEMORY_HIGH_WATERMARK -> - MemLimit; -parse_mem_limit(MemLimit) when is_float(MemLimit), MemLimit > ?MAX_VM_MEMORY_HIGH_WATERMARK -> - rabbit_log:warning( - "Memory high watermark of ~p is above the allowed maximum, falling back to ~p~n", - [MemLimit, ?MAX_VM_MEMORY_HIGH_WATERMARK] - ), - ?MAX_VM_MEMORY_HIGH_WATERMARK; -parse_mem_limit(MemLimit) -> - rabbit_log:warning( - "Memory high watermark of ~p is invalid, defaulting to ~p~n", - [MemLimit, ?DEFAULT_VM_MEMORY_HIGH_WATERMARK] - ), +parse_mem_limit(Relative) when is_float(Relative), Relative < 1 -> + Relative; +parse_mem_limit(_) -> ?DEFAULT_VM_MEMORY_HIGH_WATERMARK. + internal_update(State = #state { memory_limit = MemLimit, alarmed = Alarmed, alarm_funs = {AlarmSet, AlarmClear} }) -> - MemUsed = get_process_memory(), + MemUsed = erlang:memory(total), NewAlarmed = MemUsed > MemLimit, case {Alarmed, NewAlarmed} of {false, true} -> emit_update_info(set, MemUsed, MemLimit), @@ -377,7 +246,7 @@ internal_update(State = #state { memory_limit = MemLimit, State #state {alarmed = NewAlarmed}. emit_update_info(AlarmState, MemUsed, MemLimit) -> - rabbit_log:info( + error_logger:info_msg( "vm_memory_high_watermark ~p. Memory used:~p allowed:~p~n", [AlarmState, MemUsed, MemLimit]). @@ -417,7 +286,14 @@ cmd(Command) -> %% Original code was part of OTP and released under "Erlang Public License". get_total_memory({unix,darwin}) -> - sysctl("hw.memsize"); + File = cmd("/usr/bin/vm_stat"), + Lines = string:tokens(File, "\n"), + Dict = dict:from_list(lists:map(fun parse_line_mach/1, Lines)), + [PageSize, Inactive, Active, Free, Wired] = + [dict:fetch(Key, Dict) || + Key <- [page_size, 'Pages inactive', 'Pages active', 'Pages free', + 'Pages wired down']], + PageSize * (Inactive + Active + Free + Wired); get_total_memory({unix,freebsd}) -> PageSize = sysctl("vm.stats.vm.v_page_size"), @@ -455,6 +331,19 @@ get_total_memory({unix, aix}) -> get_total_memory(_OsType) -> unknown. +%% A line looks like "Foo bar: 123456." +parse_line_mach(Line) -> + [Name, RHS | _Rest] = string:tokens(Line, ":"), + case Name of + "Mach Virtual Memory Statistics" -> + ["(page", "size", "of", PageSize, "bytes)"] = + string:tokens(RHS, " "), + {page_size, list_to_integer(PageSize)}; + _ -> + [Value | _Rest1] = string:tokens(RHS, " ."), + {list_to_atom(Name), list_to_integer(Value)} + end. + %% A line looks like "MemTotal: 502968 kB" %% or (with broken OS/modules) "Readahead 123456 kB" parse_line_linux(Line) -> @@ -482,9 +371,9 @@ parse_line_sunos(Line) -> [Value1 | UnitsRest] = string:tokens(RHS, " "), Value2 = case UnitsRest of ["Gigabytes"] -> - list_to_integer(Value1) * ?ONE_MiB * 1024; + list_to_integer(Value1) * ?ONE_MB * 1024; ["Megabytes"] -> - list_to_integer(Value1) * ?ONE_MiB; + list_to_integer(Value1) * ?ONE_MB; ["Kilobytes"] -> list_to_integer(Value1) * 1024; _ -> @@ -506,7 +395,7 @@ parse_line_aix(Line) -> end}. sysctl(Def) -> - list_to_integer(cmd("/usr/bin/env sysctl -n " ++ Def) -- "\n"). + list_to_integer(cmd("/sbin/sysctl -n " ++ Def) -- "\n"). %% file:read_file does not work on files in /proc as it seems to get %% the size of the file first and then read that many bytes. But files diff --git a/rabbitmq-server/deps/rabbit_common/src/worker_pool.erl b/deps/rabbit/src/worker_pool.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/worker_pool.erl rename to deps/rabbit/src/worker_pool.erl index 71ed2a3..c0be486 100644 --- a/rabbitmq-server/deps/rabbit_common/src/worker_pool.erl +++ b/deps/rabbit/src/worker_pool.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(worker_pool). diff --git a/rabbitmq-server/deps/rabbit_common/src/worker_pool_sup.erl b/deps/rabbit/src/worker_pool_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/worker_pool_sup.erl rename to deps/rabbit/src/worker_pool_sup.erl index 2608f5c..f4ed4d7 100644 --- a/rabbitmq-server/deps/rabbit_common/src/worker_pool_sup.erl +++ b/deps/rabbit/src/worker_pool_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(worker_pool_sup). diff --git a/rabbitmq-server/deps/rabbit_common/src/worker_pool_worker.erl b/deps/rabbit/src/worker_pool_worker.erl similarity index 78% rename from rabbitmq-server/deps/rabbit_common/src/worker_pool_worker.erl rename to deps/rabbit/src/worker_pool_worker.erl index 23db127..bd07f0d 100644 --- a/rabbitmq-server/deps/rabbit_common/src/worker_pool_worker.erl +++ b/deps/rabbit/src/worker_pool_worker.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(worker_pool_worker). @@ -27,7 +27,6 @@ run/1]). -export([set_maximum_since_use/2]). --export([set_timeout/2, set_timeout/3, clear_timeout/1]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, prioritise_cast/3]). @@ -137,11 +136,6 @@ handle_info({'DOWN', MRef, process, CPid, _Reason}, {from, CPid, MRef}) -> handle_info({'DOWN', _MRef, process, _Pid, _Reason}, State) -> {noreply, State, hibernate}; -handle_info({timeout, Key, Fun}, State) -> - clear_timeout(Key), - Fun(), - {noreply, State, hibernate}; - handle_info(Msg, State) -> {stop, {unexpected_info, Msg}, State}. @@ -150,44 +144,3 @@ code_change(_OldVsn, State, _Extra) -> terminate(_Reason, State) -> State. - --spec set_timeout(integer(), fun(() -> any())) -> reference(). -set_timeout(Time, Fun) -> - Key = make_ref(), - set_timeout(Key, Time, Fun). - --spec set_timeout(Key, integer(), fun(() -> any())) -> Key when Key :: any(). -set_timeout(Key, Time, Fun) -> - Timeouts = get_timeouts(), - set_timeout(Key, Time, Fun, Timeouts). - --spec clear_timeout(any()) -> ok. -clear_timeout(Key) -> - NewTimeouts = cancel_timeout(Key, get_timeouts()), - put(timeouts, NewTimeouts), - ok. - -get_timeouts() -> - case get(timeouts) of - undefined -> dict:new(); - Dict -> Dict - end. - -set_timeout(Key, Time, Fun, Timeouts) -> - cancel_timeout(Key, Timeouts), - {ok, TRef} = timer:send_after(Time, {timeout, Key, Fun}), - NewTimeouts = dict:store(Key, TRef, Timeouts), - put(timeouts, NewTimeouts), - {ok, Key}. - -cancel_timeout(Key, Timeouts) -> - case dict:find(Key, Timeouts) of - {ok, TRef} -> - timer:cancel(TRef), - receive {timeout, Key, _} -> ok - after 0 -> ok - end, - dict:erase(Key, Timeouts); - error -> - Timeouts - end. diff --git a/rabbitmq-server/deps/rabbit_common/CODE_OF_CONDUCT.md b/deps/rabbit_common/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbit_common/CODE_OF_CONDUCT.md rename to deps/rabbit_common/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/CONTRIBUTING.md b/deps/rabbit_common/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/CONTRIBUTING.md rename to deps/rabbit_common/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbit_common/LICENSE b/deps/rabbit_common/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbit_common/LICENSE rename to deps/rabbit_common/LICENSE diff --git a/rabbitmq-server/deps/rabbit_common/LICENSE-MIT-Erlware-Commons b/deps/rabbit_common/LICENSE-MIT-Erlware-Commons similarity index 100% rename from rabbitmq-server/deps/rabbit_common/LICENSE-MIT-Erlware-Commons rename to deps/rabbit_common/LICENSE-MIT-Erlware-Commons diff --git a/rabbitmq-server/deps/rabbit_common/LICENSE-MPL-RabbitMQ b/deps/rabbit_common/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbit_common/LICENSE-MPL-RabbitMQ rename to deps/rabbit_common/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbit_common/development.post.mk b/deps/rabbit_common/Makefile similarity index 56% rename from rabbitmq-server/deps/rabbit_common/development.post.mk rename to deps/rabbit_common/Makefile index 65708db..678acef 100644 --- a/rabbitmq-server/deps/rabbit_common/development.post.mk +++ b/deps/rabbit_common/Makefile @@ -1,3 +1,39 @@ +PROJECT = rabbit_common + +BUILD_DEPS = rabbitmq_codegen +TEST_DEPS = mochiweb proper + +.DEFAULT_GOAL = all + +EXTRA_SOURCES += include/rabbit_framing.hrl \ + src/rabbit_framing_amqp_0_8.erl \ + src/rabbit_framing_amqp_0_9_1.erl + +.DEFAULT_GOAL = all +$(PROJECT).d:: $(EXTRA_SOURCES) + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include mk/rabbitmq-components.mk +include erlang.mk +include mk/rabbitmq-build.mk +include mk/rabbitmq-dist.mk +include mk/rabbitmq-tools.mk + +# -------------------------------------------------------------------- +# Compilation. +# -------------------------------------------------------------------- + +# $(ERTS_VER) is set in `rabbitmq-build.mk` above. +tls_atom_version_MAX_ERTS_VER = 6.0 +ifeq ($(call compare_version,$(ERTS_VER),$(tls_atom_version_MAX_ERTS_VER),<),true) +RMQ_ERLC_OPTS += -Ddefine_tls_atom_version +endif + # -------------------------------------------------------------------- # Framing sources generation. # -------------------------------------------------------------------- diff --git a/rabbitmq-server/deps/rabbit_common/codegen.py b/deps/rabbit_common/codegen.py similarity index 100% rename from rabbitmq-server/deps/rabbit_common/codegen.py rename to deps/rabbit_common/codegen.py diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/erlang.mk b/deps/rabbit_common/erlang.mk similarity index 92% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/erlang.mk rename to deps/rabbit_common/erlang.mk index 89ba561..6d2a31c 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/erlang.mk +++ b/deps/rabbit_common/erlang.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -12,23 +12,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) -export ERLANG_MK_FILENAME - -ERLANG_MK_VERSION = 2.0.0-pre.2-256-g2cce185 -ERLANG_MK_WITHOUT = - -# Make 3.81 and 3.82 are deprecated. - -ifeq ($(MAKE_VERSION),3.81) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif -ifeq ($(MAKE_VERSION),3.82) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 # Core configuration. @@ -37,7 +25,6 @@ PROJECT := $(strip $(PROJECT)) PROJECT_VERSION ?= rolling PROJECT_MOD ?= $(PROJECT)_app -PROJECT_ENV ?= [] # Verbosity. @@ -98,8 +85,6 @@ all:: deps app rel rel:: $(verbose) : -relup:: deps app - check:: tests clean:: clean-crashdump @@ -117,7 +102,7 @@ distclean-tmp: help:: $(verbose) printf "%s\n" \ "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ - "Copyright (c) 2013-2016 Loïc Hoguin " \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ "" \ "Usage: [V=1] $(MAKE) [target]..." \ "" \ @@ -165,7 +150,30 @@ else core_native_path = $1 endif -core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$1) $2 +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) @@ -185,14 +193,13 @@ ERLANG_MK_COMMIT ?= ERLANG_MK_BUILD_CONFIG ?= build.config ERLANG_MK_BUILD_DIR ?= .erlang.mk.build -erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) ifdef ERLANG_MK_COMMIT cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) endif if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - $(MAKE) -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk rm -rf $(ERLANG_MK_BUILD_DIR) @@ -279,14 +286,6 @@ pkg_apns_fetch = git pkg_apns_repo = https://github.com/inaka/apns4erl pkg_apns_commit = master -PACKAGES += asciideck -pkg_asciideck_name = asciideck -pkg_asciideck_description = Asciidoc for Erlang. -pkg_asciideck_homepage = https://ninenines.eu -pkg_asciideck_fetch = git -pkg_asciideck_repo = https://github.com/ninenines/asciideck -pkg_asciideck_commit = master - PACKAGES += azdht pkg_azdht_name = azdht pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang @@ -407,14 +406,6 @@ pkg_bootstrap_fetch = git pkg_bootstrap_repo = https://github.com/schlagert/bootstrap pkg_bootstrap_commit = master -PACKAGES += boss -pkg_boss_name = boss -pkg_boss_description = Erlang web MVC, now featuring Comet -pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_fetch = git -pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_commit = master - PACKAGES += boss_db pkg_boss_db_name = boss_db pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang @@ -423,6 +414,14 @@ pkg_boss_db_fetch = git pkg_boss_db_repo = https://github.com/ErlyORM/boss_db pkg_boss_db_commit = master +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + PACKAGES += brod pkg_brod_name = brod pkg_brod_description = Kafka client in Erlang @@ -567,13 +566,13 @@ pkg_cloudi_service_api_requests_fetch = git pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests pkg_cloudi_service_api_requests_commit = master -PACKAGES += cloudi_service_db -pkg_cloudi_service_db_name = cloudi_service_db -pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) -pkg_cloudi_service_db_homepage = http://cloudi.org/ -pkg_cloudi_service_db_fetch = git -pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db -pkg_cloudi_service_db_commit = master +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master PACKAGES += cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra @@ -583,14 +582,6 @@ pkg_cloudi_service_db_cassandra_fetch = git pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_commit = master -PACKAGES += cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service -pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ -pkg_cloudi_service_db_cassandra_cql_fetch = git -pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_commit = master - PACKAGES += cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service @@ -647,6 +638,14 @@ pkg_cloudi_service_db_tokyotyrant_fetch = git pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_commit = master +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + PACKAGES += cloudi_service_filesystem pkg_cloudi_service_filesystem_name = cloudi_service_filesystem pkg_cloudi_service_filesystem_description = Filesystem CloudI Service @@ -1039,14 +1038,6 @@ pkg_edown_fetch = git pkg_edown_repo = https://github.com/uwiger/edown pkg_edown_commit = master -PACKAGES += eep -pkg_eep_name = eep -pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy -pkg_eep_homepage = https://github.com/virtan/eep -pkg_eep_fetch = git -pkg_eep_repo = https://github.com/virtan/eep -pkg_eep_commit = master - PACKAGES += eep_app pkg_eep_app_name = eep_app pkg_eep_app_description = Embedded Event Processing @@ -1055,6 +1046,14 @@ pkg_eep_app_fetch = git pkg_eep_app_repo = https://github.com/darach/eep-erl pkg_eep_app_commit = master +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + PACKAGES += efene pkg_efene_name = efene pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX @@ -1239,14 +1238,6 @@ pkg_eqm_fetch = git pkg_eqm_repo = https://github.com/loucash/eqm pkg_eqm_commit = master -PACKAGES += eredis -pkg_eredis_name = eredis -pkg_eredis_description = Erlang Redis client -pkg_eredis_homepage = https://github.com/wooga/eredis -pkg_eredis_fetch = git -pkg_eredis_repo = https://github.com/wooga/eredis -pkg_eredis_commit = master - PACKAGES += eredis_pool pkg_eredis_pool_name = eredis_pool pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. @@ -1255,6 +1246,14 @@ pkg_eredis_pool_fetch = git pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_commit = master +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + PACKAGES += erl_streams pkg_erl_streams_name = erl_streams pkg_erl_streams_description = Streams in Erlang @@ -1543,14 +1542,6 @@ pkg_etap_fetch = git pkg_etap_repo = https://github.com/ngerakines/etap pkg_etap_commit = master -PACKAGES += etest -pkg_etest_name = etest -pkg_etest_description = A lightweight, convention over configuration test framework for Erlang -pkg_etest_homepage = https://github.com/wooga/etest -pkg_etest_fetch = git -pkg_etest_repo = https://github.com/wooga/etest -pkg_etest_commit = master - PACKAGES += etest_http pkg_etest_http_name = etest_http pkg_etest_http_description = etest Assertions around HTTP (client-side) @@ -1559,6 +1550,14 @@ pkg_etest_http_fetch = git pkg_etest_http_repo = https://github.com/wooga/etest_http pkg_etest_http_commit = master +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + PACKAGES += etoml pkg_etoml_name = etoml pkg_etoml_description = TOML language erlang parser @@ -1567,14 +1566,6 @@ pkg_etoml_fetch = git pkg_etoml_repo = https://github.com/kalta/etoml pkg_etoml_commit = master -PACKAGES += eunit -pkg_eunit_name = eunit -pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. -pkg_eunit_homepage = https://github.com/richcarl/eunit -pkg_eunit_fetch = git -pkg_eunit_repo = https://github.com/richcarl/eunit -pkg_eunit_commit = master - PACKAGES += eunit_formatters pkg_eunit_formatters_name = eunit_formatters pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. @@ -1583,6 +1574,14 @@ pkg_eunit_formatters_fetch = git pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_commit = master +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + PACKAGES += euthanasia pkg_euthanasia_name = euthanasia pkg_euthanasia_description = Merciful killer for your Erlang processes @@ -1600,7 +1599,7 @@ pkg_evum_repo = https://github.com/msantos/evum pkg_evum_commit = master PACKAGES += exec -pkg_exec_name = erlexec +pkg_exec_name = exec pkg_exec_description = Execute and control OS processes from Erlang/OTP. pkg_exec_homepage = http://saleyn.github.com/erlexec pkg_exec_fetch = git @@ -1719,14 +1718,6 @@ pkg_fn_fetch = git pkg_fn_repo = https://github.com/reiddraper/fn pkg_fn_commit = master -PACKAGES += folsom -pkg_folsom_name = folsom -pkg_folsom_description = Expose Erlang Events and Metrics -pkg_folsom_homepage = https://github.com/boundary/folsom -pkg_folsom_fetch = git -pkg_folsom_repo = https://github.com/boundary/folsom -pkg_folsom_commit = master - PACKAGES += folsom_cowboy pkg_folsom_cowboy_name = folsom_cowboy pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. @@ -1735,6 +1726,14 @@ pkg_folsom_cowboy_fetch = git pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_commit = master +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + PACKAGES += folsomite pkg_folsomite_name = folsomite pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics @@ -2095,14 +2094,6 @@ pkg_jesse_fetch = git pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master -PACKAGES += jiffy -pkg_jiffy_name = jiffy -pkg_jiffy_description = JSON NIFs for Erlang. -pkg_jiffy_homepage = https://github.com/davisp/jiffy -pkg_jiffy_fetch = git -pkg_jiffy_repo = https://github.com/davisp/jiffy -pkg_jiffy_commit = master - PACKAGES += jiffy_v pkg_jiffy_v_name = jiffy_v pkg_jiffy_v_description = JSON validation utility @@ -2111,6 +2102,14 @@ pkg_jiffy_v_fetch = git pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v pkg_jiffy_v_commit = master +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + PACKAGES += jobs pkg_jobs_name = jobs pkg_jobs_description = a Job scheduler for load regulation @@ -2127,14 +2126,6 @@ pkg_joxa_fetch = git pkg_joxa_repo = https://github.com/joxa/joxa pkg_joxa_commit = master -PACKAGES += json -pkg_json_name = json -pkg_json_description = a high level json library for erlang (17.0+) -pkg_json_homepage = https://github.com/talentdeficit/json -pkg_json_fetch = git -pkg_json_repo = https://github.com/talentdeficit/json -pkg_json_commit = master - PACKAGES += json_rec pkg_json_rec_name = json_rec pkg_json_rec_description = JSON to erlang record @@ -2143,6 +2134,14 @@ pkg_json_rec_fetch = git pkg_json_rec_repo = https://github.com/justinkirby/json_rec pkg_json_rec_commit = master +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + PACKAGES += jsone pkg_jsone_name = jsone pkg_jsone_description = An Erlang library for encoding, decoding JSON data. @@ -2183,14 +2182,6 @@ pkg_jsx_fetch = git pkg_jsx_repo = https://github.com/talentdeficit/jsx pkg_jsx_commit = master -PACKAGES += kafka -pkg_kafka_name = kafka -pkg_kafka_description = Kafka consumer and producer in Erlang -pkg_kafka_homepage = https://github.com/wooga/kafka-erlang -pkg_kafka_fetch = git -pkg_kafka_repo = https://github.com/wooga/kafka-erlang -pkg_kafka_commit = master - PACKAGES += kafka_protocol pkg_kafka_protocol_name = kafka_protocol pkg_kafka_protocol_description = Kafka protocol Erlang library @@ -2199,6 +2190,14 @@ pkg_kafka_protocol_fetch = git pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git pkg_kafka_protocol_commit = master +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + PACKAGES += kai pkg_kai_name = kai pkg_kai_description = DHT storage by Takeshi Inoue @@ -2295,14 +2294,6 @@ pkg_kvs_fetch = git pkg_kvs_repo = https://github.com/synrc/kvs pkg_kvs_commit = master -PACKAGES += lager -pkg_lager_name = lager -pkg_lager_description = A logging framework for Erlang/OTP. -pkg_lager_homepage = https://github.com/basho/lager -pkg_lager_fetch = git -pkg_lager_repo = https://github.com/basho/lager -pkg_lager_commit = master - PACKAGES += lager_amqp_backend pkg_lager_amqp_backend_name = lager_amqp_backend pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend @@ -2319,6 +2310,14 @@ pkg_lager_syslog_fetch = git pkg_lager_syslog_repo = https://github.com/basho/lager_syslog pkg_lager_syslog_commit = master +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + PACKAGES += lambdapad pkg_lambdapad_name = lambdapad pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. @@ -2575,14 +2574,6 @@ pkg_mixer_fetch = git pkg_mixer_repo = https://github.com/chef/mixer pkg_mixer_commit = master -PACKAGES += mochiweb -pkg_mochiweb_name = mochiweb -pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. -pkg_mochiweb_homepage = https://github.com/mochi/mochiweb -pkg_mochiweb_fetch = git -pkg_mochiweb_repo = https://github.com/mochi/mochiweb -pkg_mochiweb_commit = master - PACKAGES += mochiweb_xpath pkg_mochiweb_xpath_name = mochiweb_xpath pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser @@ -2591,6 +2582,14 @@ pkg_mochiweb_xpath_fetch = git pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_commit = master +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + PACKAGES += mockgyver pkg_mockgyver_name = mockgyver pkg_mockgyver_description = A mocking library for Erlang @@ -3063,14 +3062,6 @@ pkg_quickrand_fetch = git pkg_quickrand_repo = https://github.com/okeuday/quickrand pkg_quickrand_commit = master -PACKAGES += rabbit -pkg_rabbit_name = rabbit -pkg_rabbit_description = RabbitMQ Server -pkg_rabbit_homepage = https://www.rabbitmq.com/ -pkg_rabbit_fetch = git -pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git -pkg_rabbit_commit = master - PACKAGES += rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak @@ -3079,6 +3070,14 @@ pkg_rabbit_exchange_type_riak_fetch = git pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_commit = master +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + PACKAGES += rack pkg_rack_name = rack pkg_rack_description = Rack handler for erlang @@ -3495,14 +3494,6 @@ pkg_smother_fetch = git pkg_smother_repo = https://github.com/ramsay-t/Smother pkg_smother_commit = master -PACKAGES += snappyer -pkg_snappyer_name = snappyer -pkg_snappyer_description = Snappy as nif for Erlang -pkg_snappyer_homepage = https://github.com/zmstone/snappyer -pkg_snappyer_fetch = git -pkg_snappyer_repo = https://github.com/zmstone/snappyer.git -pkg_snappyer_commit = master - PACKAGES += social pkg_social_name = social pkg_social_description = Cowboy handler for social login via OAuth2 providers @@ -3551,14 +3542,6 @@ pkg_stable_fetch = git pkg_stable_repo = https://github.com/dvv/stable pkg_stable_commit = master -PACKAGES += statebox -pkg_statebox_name = statebox -pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. -pkg_statebox_homepage = https://github.com/mochi/statebox -pkg_statebox_fetch = git -pkg_statebox_repo = https://github.com/mochi/statebox -pkg_statebox_commit = master - PACKAGES += statebox_riak pkg_statebox_riak_name = statebox_riak pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. @@ -3567,6 +3550,14 @@ pkg_statebox_riak_fetch = git pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak pkg_statebox_riak_commit = master +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + PACKAGES += statman pkg_statman_name = statman pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM @@ -3735,14 +3726,6 @@ pkg_tirerl_fetch = git pkg_tirerl_repo = https://github.com/inaka/tirerl pkg_tirerl_commit = master -PACKAGES += toml -pkg_toml_name = toml -pkg_toml_description = TOML (0.4.0) config parser -pkg_toml_homepage = http://dozzie.jarowit.net/trac/wiki/TOML -pkg_toml_fetch = git -pkg_toml_repo = https://github.com/dozzie/toml -pkg_toml_commit = v0.2.0 - PACKAGES += traffic_tools pkg_traffic_tools_name = traffic_tools pkg_traffic_tools_description = Simple traffic limiting library @@ -4079,7 +4062,7 @@ pkg_zucchini_fetch = git pkg_zucchini_repo = https://github.com/devinus/zucchini pkg_zucchini_commit = master -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: search @@ -4106,10 +4089,10 @@ else $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-deps clean-tmp-deps.log +.PHONY: distclean-deps # Configuration. @@ -4129,32 +4112,11 @@ export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR -# External "early" plugins (see core/plugins.mk for regular plugins). -# They both use the core_dep_plugin macro. - -define core_dep_plugin -ifeq ($(2),$(PROJECT)) --include $$(patsubst $(PROJECT)/%,%,$(1)) -else --include $(DEPS_DIR)/$(1) - -$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; -endif -endef - -DEP_EARLY_PLUGINS ?= - -$(foreach p,$(DEP_EARLY_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/early-plugins.mk,$p)))) - dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) -LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$(a)),$(APPS_DIR)/$(a))) ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) @@ -4177,7 +4139,10 @@ dep_verbose = $(dep_verbose_$(V)) # Core targets. -apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log endif @@ -4185,42 +4150,36 @@ endif # Create ebin directory for all apps to make sure Erlang recognizes them # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. -ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - mkdir -p $$dep/ebin; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ done -endif -# at the toplevel: if LOCAL_DEPS is defined with at least one local app, only -# compile that list of apps. otherwise, compile everything. -# within an app: compile all LOCAL_DEPS that are (uncompiled) local apps - $(verbose) set -e; for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ - $(MAKE) -C $$dep IS_APP=1; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ fi \ done - -clean-tmp-deps.log: -ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log endif ifneq ($(SKIP_DEPS),) deps:: else -deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) set -e; for dep in $(ALL_DEPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ - $(MAKE) -C $$dep IS_DEP=1; \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ else \ - echo "Error: No Makefile to build dependency $$dep." >&2; \ + echo "Error: No Makefile to build dependency $$dep."; \ exit 2; \ fi \ fi \ @@ -4234,18 +4193,17 @@ endif # in practice only Makefile is needed so far. define dep_autopatch if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ - rm -rf $(DEPS_DIR)/$1/ebin/; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ $(call dep_autopatch_erlang_mk,$(1)); \ elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ - if [ -f $(DEPS_DIR)/$1/rebar.lock ]; then \ - $(call dep_autopatch2,$1); \ - elif [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ @@ -4257,14 +4215,11 @@ define dep_autopatch endef define dep_autopatch2 - ! test -f $(DEPS_DIR)/$1/ebin/$1.app || \ - mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ - rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ fi; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ - if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script -o -f $(DEPS_DIR)/$1/rebar.lock ]; then \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ $(call dep_autopatch_fetch_rebar); \ $(call dep_autopatch_rebar,$(1)); \ else \ @@ -4276,15 +4231,11 @@ define dep_autopatch_noop printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile endef -# Replace "include erlang.mk" with a line that will load the parent Erlang.mk -# if given. Do it for all 3 possible Makefile file names. +# Overwrite erlang.mk with the current file by default. ifeq ($(NO_AUTOPATCH_ERLANG_MK),) define dep_autopatch_erlang_mk - $t for f in Makefile makefile GNUmakefile; do \ - if [ -f $(DEPS_DIR)/$1/$$f ]; then \ - sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \ - fi \ - done + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk endef else define dep_autopatch_erlang_mk @@ -4303,7 +4254,7 @@ define dep_autopatch_fetch_rebar if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ - git checkout -q 576e12171ab8d69b048b827b92aa65d067deea01; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ $(MAKE); \ cd -; \ fi @@ -4320,7 +4271,6 @@ endef define dep_autopatch_rebar.erl application:load(rebar), application:set_env(rebar, log_level, debug), - rmemo:start(), Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of {ok, Conf0} -> Conf0; _ -> [] @@ -4474,9 +4424,9 @@ define dep_autopatch_rebar.erl [] -> ok; _ -> Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), - PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -4515,7 +4465,7 @@ define dep_autopatch_rebar.erl "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", - [[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], Output, ": $$\(foreach ext,.c .C .cc .cpp,", "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", @@ -4527,7 +4477,7 @@ define dep_autopatch_rebar.erl end, [PortSpec(S) || S <- PortSpecs] end, - Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of false -> ok; @@ -4575,6 +4525,22 @@ define dep_autopatch_rebar.erl halt() endef +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", @@ -4622,16 +4588,21 @@ define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef -define dep_fetch_ln - ln -s $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() endef # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex - mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ - $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ - https://s3.amazonaws.com/s3.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ - tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); endef define dep_fetch_fail @@ -4661,7 +4632,7 @@ $(DEPS_DIR)/$(call dep_name,$1): $(eval DEP_NAME := $(call dep_name,$1)) $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ - echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) @@ -4703,15 +4674,15 @@ ifndef IS_APP clean:: clean-apps clean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep clean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ done distclean:: distclean-apps distclean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep distclean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ done endif @@ -4731,7 +4702,85 @@ ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log -# Copyright (c) 2015-2016, Loïc Hoguin +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Verbosity. @@ -4750,9 +4799,10 @@ endef define compile_proto.erl [begin + Dir = filename:dirname(filename:dirname(F)), protobuffs_compile:generate_source(F, - [{output_include_dir, "./include"}, - {output_src_dir, "./ebin"}]) + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) end || F <- string:tokens("$(1)", " ")], halt(). endef @@ -4762,7 +4812,7 @@ ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) $(if $(strip $?),$(call compile_proto,$?)) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app @@ -4776,8 +4826,6 @@ COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) ERLC_EXCLUDE ?= ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) -ERLC_ASN1_OPTS ?= - ERLC_MIB_OPTS ?= COMPILE_MIB_FIRST ?= COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) @@ -4827,27 +4875,25 @@ endif ifeq ($(wildcard src/$(PROJECT_MOD).erl),) define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} ]}. endef else define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {mod, {$(PROJECT_MOD), []}}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {mod, {$(PROJECT_MOD), []}} ]}. endef endif @@ -4857,10 +4903,8 @@ app-build: ebin/$(PROJECT).app # Source files. -ALL_SRC_FILES := $(sort $(call core_find,src/,*)) - -ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES)) -CORE_FILES := $(filter %.core,$(ALL_SRC_FILES)) +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) # ASN.1 files. @@ -4870,7 +4914,7 @@ ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) define compile_asn1 $(verbose) mkdir -p include/ - $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $(1) + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) $(verbose) mv asn1/*.erl src/ $(verbose) mv asn1/*.hrl include/ $(verbose) mv asn1/*.asn1db include/ @@ -4893,16 +4937,16 @@ endif # Leex and Yecc files. -XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES)) +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) ERL_FILES += $(XRL_ERL_FILES) -YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES)) +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) ERL_FILES += $(YRL_ERL_FILES) $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) - $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) # Erlang and Core Erlang files. @@ -4952,12 +4996,7 @@ define makedep.erl (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, import, {Imp, _}) -> - IsFile = - case lists:keyfind(Imp, 1, Modules) of - false -> false; - {_, FilePath} -> filelib:is_file(FilePath) - end, - case IsFile of + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of false -> ok; true -> Add(Mod, Imp) end; @@ -4981,17 +5020,9 @@ define makedep.erl end || F <- ErlFiles], Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], - TargetPath = fun(Target) -> - case lists:keyfind(Target, 1, Modules) of - false -> ""; - {_, DepFile} -> - DirSubname = tl(string:tokens(filename:dirname(DepFile), "/")), - string:join(DirSubname ++ [atom_to_list(Target)], "/") - end - end, ok = file:write_file("$(1)", [ [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], - "\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n" + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" ]), halt() endef @@ -5004,18 +5035,18 @@ endif ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) if test -f $@; then \ + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ fi - $(verbose) touch $@ + @touch $@ $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change endif -include $(wildcard $(PROJECT).d) +-include $(PROJECT).d ebin/$(PROJECT).app:: ebin/ @@ -5034,7 +5065,7 @@ ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.s $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) - $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ > ebin/$(PROJECT).app else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ @@ -5058,7 +5089,6 @@ clean-app: endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5076,10 +5106,10 @@ ifneq ($(SKIP_DEPS),) doc-deps: else doc-deps: $(ALL_DOC_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rel-deps @@ -5096,10 +5126,10 @@ ifneq ($(SKIP_DEPS),) rel-deps: else rel-deps: $(ALL_REL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: test-deps test-dir test-build clean-test-dir @@ -5121,7 +5151,7 @@ ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done endif ifneq ($(wildcard $(TEST_DIR)),) @@ -5154,7 +5184,7 @@ ifneq ($(wildcard $(TEST_DIR)/*.beam),) endif endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rebar.config @@ -5190,90 +5220,54 @@ $(eval export _compat_rebar_config) rebar.config: $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck) +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc -.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual - -# Core targets. +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 docs:: asciidoc -distclean:: distclean-asciidoc-guide distclean-asciidoc-manual - -# Plugin-specific targets. - asciidoc: asciidoc-guide asciidoc-manual -# User guide. - ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else -asciidoc-guide: distclean-asciidoc-guide doc-deps +asciidoc-guide: distclean-asciidoc doc-deps a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ - -distclean-asciidoc-guide: - $(gen_verbose) rm -rf doc/html/ doc/guide.pdf endif -# Man pages. - -ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc) - -ifeq ($(ASCIIDOC_MANUAL_FILES),) +ifeq ($(wildcard doc/src/manual/*.asciidoc),) asciidoc-manual: else - -# Configuration. - -MAN_INSTALL_PATH ?= /usr/local/share/man -MAN_SECTIONS ?= 3 7 -MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/') -MAN_VERSION ?= $(PROJECT_VERSION) - -# Plugin-specific targets. - -define asciidoc2man.erl -try - [begin - io:format(" ADOC ~s~n", [F]), - ok = asciideck:to_manpage(asciideck:parse_file(F), #{ - compress => gzip, - outdir => filename:dirname(F), - extra2 => "$(MAN_PROJECT) $(MAN_VERSION)", - extra3 => "$(MAN_PROJECT) Function Reference" - }) - end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]], - halt(0) -catch C:E -> - io:format("Exception ~p:~p~nStacktrace: ~p~n", [C, E, erlang:get_stacktrace()]), - halt(1) -end. -endef - -asciidoc-manual:: doc-deps - -asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) - $(call erlang,$(call asciidoc2man.erl,$?)) - $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done install-docs:: install-asciidoc install-asciidoc: asciidoc-manual - $(foreach s,$(MAN_SECTIONS),\ - mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ - install -g `id -u` -o `id -g` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) - -distclean-asciidoc-manual: - $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) -endif + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done endif -# Copyright (c) 2014-2016, Loïc Hoguin +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates @@ -5330,7 +5324,7 @@ ifdef SP define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 # Whitespace to be used when creating files from templates. SP = $(SP) @@ -5340,7 +5334,7 @@ else define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 endef endif @@ -5348,7 +5342,7 @@ endif define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk endef @@ -5368,7 +5362,7 @@ stop(_State) -> endef define bs_relx_config -{release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. +{release, {$p_release, "1"}, [$p]}. {extended_start_script, true}. {sys_config, "rel/sys.config"}. {vm_args, "rel/vm.args"}. @@ -5719,6 +5713,9 @@ endif ifndef t $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif +ifndef tpl_$(t) + $(error Unknown template) +endif ifndef n $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif @@ -5731,7 +5728,7 @@ endif list-templates: $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) -# Copyright (c) 2014-2016, Loïc Hoguin +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-c_src distclean-c_src-env @@ -5966,94 +5963,56 @@ else $(call render_template,bs_erl_nif,src/$n.erl) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ci ci-prepare ci-setup distclean-kerl - -CI_OTP ?= -CI_HIPE ?= -CI_ERLLVM ?= - -ifeq ($(CI_VM),native) -ERLC_OPTS += +native -TEST_ERLC_OPTS += +native -else ifeq ($(CI_VM),erllvm) -ERLC_OPTS += +native +'{hipe, [to_llvm]}' -TEST_ERLC_OPTS += +native +'{hipe, [to_llvm]}' -endif - -ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) -ci:: -else - -ifeq ($(strip $(KERL)),) -KERL := $(ERLANG_MK_TMP)/kerl/kerl -endif +.PHONY: ci ci-setup distclean-kerl +KERL ?= $(CURDIR)/kerl export KERL -KERL_GIT ?= https://github.com/kerl/kerl -KERL_COMMIT ?= master - -KERL_MAKEFLAGS ?= +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl OTP_GIT ?= https://github.com/erlang/otp CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= -ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) -ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) ci-setup:: -ci-extra:: - ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target -ci-$1: $(CI_INSTALL_DIR)/$2 - $(verbose) $(MAKE) --no-print-directory clean +ci-$(1): $(CI_INSTALL_DIR)/$(1) $(ci_verbose) \ - PATH="$(CI_INSTALL_DIR)/$2/bin:$(PATH)" \ - CI_OTP_RELEASE="$1" \ - CT_OPTS="-label $1" \ - CI_VM="$3" \ - $(MAKE) ci-setup tests - $(verbose) $(MAKE) --no-print-directory ci-extra + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests endef -$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) -$(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) -$(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) define ci_otp_target ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) $(CI_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) build git $(OTP_GIT) $(1) $(1) $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) endif endef $(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) -define ci_hipe_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$1-native),) -$(CI_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(CI_INSTALL_DIR)/$1-native -endif -endef - -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call ci_hipe_target,$(otp)))) - $(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl - $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) $(verbose) chmod +x $(KERL) help:: @@ -6070,7 +6029,7 @@ distclean-kerl: $(gen_verbose) rm -rf $(KERL) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ct apps-ct distclean-ct @@ -6078,14 +6037,11 @@ endif # Configuration. CT_OPTS ?= - ifneq ($(wildcard $(TEST_DIR)),) -ifndef CT_SUITES -CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) -endif + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= endif -CT_SUITES ?= -CT_LOGS_DIR ?= $(CURDIR)/logs # Core targets. @@ -6108,18 +6064,15 @@ CT_RUN = ct_run \ -noinput \ -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ - -logdir $(CT_LOGS_DIR) + -logdir $(CURDIR)/logs ifeq ($(CT_SUITES),) ct: $(if $(IS_APP),,apps-ct) else -# We do not run tests if we are in an apps/* with no test directory. -ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) ct: test-build $(if $(IS_APP),,apps-ct) - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif -endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target @@ -6145,16 +6098,16 @@ endif define ct_suite_target ct-$(1): test-build - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) distclean-ct: - $(gen_verbose) rm -rf $(CT_LOGS_DIR) + $(gen_verbose) rm -rf $(CURDIR)/logs/ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: plt distclean-plt dialyze @@ -6198,10 +6151,7 @@ define filter_opts.erl endef $(DIALYZER_PLT): deps app - $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ - while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) - $(verbose) dialyzer --build_plt --apps erts kernel stdlib \ - $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) plt: $(DIALYZER_PLT) @@ -6215,7 +6165,7 @@ dialyze: $(DIALYZER_PLT) endif $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-edoc edoc @@ -6223,20 +6173,10 @@ endif # Configuration. EDOC_OPTS ?= -EDOC_SRC_DIRS ?= - -define edoc.erl - SrcPaths = lists:foldl(fun(P, Acc) -> - filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc - end, [], [$(call comma_list,$(patsubst %,'%',$(EDOC_SRC_DIRS)))]), - DefaultOpts = [{source_path, SrcPaths}, {subpackages, false}], - edoc:application($(1), ".", [$(2)] ++ DefaultOpts), - halt(0). -endef # Core targets. -ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),) +ifneq ($(wildcard doc/overview.edoc),) docs:: edoc endif @@ -6245,91 +6185,30 @@ distclean:: distclean-edoc # Plugin-specific targets. edoc: distclean-edoc doc-deps - $(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS))) + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' distclean-edoc: $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info -# Copyright (c) 2013-2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# Configuration. - -DTL_FULL_PATH ?= -DTL_PATH ?= templates/ -DTL_SUFFIX ?= _dtl -DTL_OPTS ?= - -# Verbosity. - -dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); -dtl_verbose = $(dtl_verbose_$(V)) - -# Core targets. - -DTL_PATH := $(abspath $(DTL_PATH)) -DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) - -ifneq ($(DTL_FILES),) - -DTL_NAMES = $(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)) -DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) -BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) - -ifneq ($(words $(DTL_FILES)),0) -# Rebuild templates when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) - @mkdir -p $(ERLANG_MK_TMP) - @if test -f $@; then \ - touch $(DTL_FILES); \ - fi - @touch $@ - -ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl -endif - -define erlydtl_compile.erl - [begin - Module0 = case "$(strip $(DTL_FULL_PATH))" of - "" -> - filename:basename(F, ".dtl"); - _ -> - "$(DTL_PATH)/" ++ F2 = filename:rootname(F, ".dtl"), - re:replace(F2, "/", "_", [{return, list}, global]) - end, - Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), - case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of - ok -> ok; - {ok, _} -> ok - end - end || F <- string:tokens("$(1)", " ")], - halt(). -endef - -ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ - $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ - -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) - -endif - -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2014, Dave Cottlehuber +# Copyright (c) 2014 Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-escript escript escript-zip +.PHONY: distclean-escript escript # Configuration. ESCRIPT_NAME ?= $(PROJECT) ESCRIPT_FILE ?= $(ESCRIPT_NAME) -ESCRIPT_SHEBANG ?= /usr/bin/env escript ESCRIPT_COMMENT ?= This is an -*- erlang -*- file -ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME) -ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null) -ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" # Core targets. @@ -6342,28 +6221,44 @@ help:: # Plugin-specific targets. -escript-zip:: deps app - $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) - $(verbose) rm -f $(ESCRIPT_ZIP_FILE) - $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* -ifneq ($(DEPS),) - $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ - `cat $(ERLANG_MK_TMP)/deps.log | sed 's/^$(subst /,\/,$(DEPS_DIR))\///' | sed 's/$$/\/ebin\/\*/'` -endif +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef -escript:: escript-zip - $(gen_verbose) printf "%s\n" \ - "#!$(ESCRIPT_SHEBANG)" \ - "%% $(ESCRIPT_COMMENT)" \ - "%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE) - $(verbose) cat $(ESCRIPT_ZIP_FILE) >> $(ESCRIPT_FILE) - $(verbose) chmod +x $(ESCRIPT_FILE) +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) distclean-escript: - $(gen_verbose) rm -f $(ESCRIPT_FILE) + $(gen_verbose) rm -f $(ESCRIPT_NAME) -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: eunit apps-eunit @@ -6427,31 +6322,23 @@ eunit: test-build $(if $(IS_APP),,apps-eunit) ifneq ($(ALL_APPS_DIRS),) apps-eunit: - $(verbose) eunit_retcode=0 ; for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; \ - [ $$? -ne 0 ] && eunit_retcode=1 ; done ; \ - exit $$eunit_retcode + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done endif endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: relx-rel relx-relup distclean-relx-rel run +.PHONY: relx-rel distclean-relx-rel distclean-relx run # Configuration. -RELX ?= $(ERLANG_MK_TMP)/relx +RELX ?= $(CURDIR)/relx RELX_CONFIG ?= $(CURDIR)/relx.config RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel -RELX_REL_EXT ?= -RELX_TAR ?= 1 - -ifdef SFX - RELX_TAR = 1 -endif ifeq ($(firstword $(RELX_OPTS)),-o) RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) @@ -6464,12 +6351,10 @@ endif ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) rel:: relx-rel - -relup:: relx-relup endif endif -distclean:: distclean-relx-rel +distclean:: distclean-relx-rel distclean-relx # Plugin-specific targets. @@ -6478,14 +6363,14 @@ $(RELX): $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release $(if $(filter 1,$(RELX_TAR)),tar) - -relx-relup: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release relup $(if $(filter 1,$(RELX_TAR)),tar) + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) @@ -6493,28 +6378,16 @@ run: else define get_relx_release.erl - {ok, Config} = file:consult("$(call core_native_path,$(RELX_CONFIG))"), - {release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config), - Vsn = case Vsn0 of - {cmd, Cmd} -> os:cmd(Cmd); - semver -> ""; - {semver, _} -> ""; - VsnStr -> Vsn0 - end, - io:format("~s ~s", [Name, Vsn]), + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), halt(0). endef -RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) -RELX_REL_NAME := $(word 1,$(RELX_REL)) -RELX_REL_VSN := $(word 2,$(RELX_REL)) - -ifeq ($(PLATFORM),msys2) -RELX_REL_EXT := .cmd -endif +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` run: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) console + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console help:: $(verbose) printf "%s\n" "" \ @@ -6523,8 +6396,8 @@ help:: endif -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: shell @@ -6549,26 +6422,12 @@ help:: $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) build-shell-deps: $(ALL_SHELL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done shell: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) -# Copyright (c) 2017, Jean-Sébastien Pédron -# This file is contributed to erlang.mk and subject to the terms of the ISC License. - -.PHONY: show-ERL_LIBS show-ERLC_OPTS show-TEST_ERLC_OPTS - -show-ERL_LIBS: - @echo $(ERL_LIBS) - -show-ERLC_OPTS: - @$(foreach opt,$(ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -show-TEST_ERLC_OPTS: - @$(foreach opt,$(TEST_ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) @@ -6579,7 +6438,7 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl - code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), try case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); @@ -6611,7 +6470,6 @@ triq: test-build endif endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Erlang Solutions Ltd. # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6628,14 +6486,14 @@ endif XREFR ?= $(CURDIR)/xrefr export XREFR -XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/1.1.0/xrefr +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr # Core targets. help:: - $(verbose) printf '%s\n' '' \ - 'Xref targets:' \ - ' xref Run Xrefr using $$XREF_CONFIG as config file if defined' + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" distclean:: distclean-xref @@ -6651,8 +6509,7 @@ xref: deps app $(XREFR) distclean-xref: $(gen_verbose) rm -rf $(XREFR) -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2015, Viktor Söderqvist +# Copyright 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR = cover @@ -6661,7 +6518,6 @@ COVER_REPORT_DIR = cover ifdef COVER ifdef CT_RUN -ifneq ($(wildcard $(TEST_DIR)),) # All modules in 'ebin' COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) @@ -6676,7 +6532,6 @@ $(TEST_DIR)/ct.cover.spec: CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif -endif # Core targets @@ -6698,7 +6553,7 @@ help:: "Cover targets:" \ " cover-report Generate a HTML coverage report from previously collected" \ " cover data." \ - " all.coverdata Merge all coverdata files into all.coverdata." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ "" \ "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ "target tests additionally generates a HTML coverage report from the combined" \ @@ -6711,16 +6566,13 @@ COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) .PHONY: coverdata-clean coverdata-clean: - $(gen_verbose) rm -f *.coverdata $(TEST_DIR)/ct.cover.spec + $(gen_verbose) rm -f *.coverdata ct.cover.spec # Merge all coverdata files into one. -define cover_export.erl - $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) - cover:export("$@"), halt(0). -endef - all.coverdata: $(COVERDATA) - $(gen_verbose) $(call erlang,$(cover_export.erl)) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' # These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to # empty if you want the coverdata files but not the HTML report. @@ -6738,7 +6590,7 @@ else # Modules which include eunit.hrl always contain one line without coverage # because eunit defines test/0 which is never called. We compensate for this. EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ - grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) define cover_report.erl @@ -6773,71 +6625,12 @@ define cover_report.erl endef cover-report: - $(verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) $(gen_verbose) $(call erlang,$(cover_report.erl)) endif endif # ifneq ($(COVER_REPORT_DIR),) -# Copyright (c) 2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -.PHONY: sfx - -ifdef RELX_REL -ifdef SFX - -# Configuration. - -SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz -SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run - -# Core targets. - -rel:: sfx - -# Plugin-specific targets. - -define sfx_stub -#!/bin/sh - -TMPDIR=`mktemp -d` -ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0` -FILENAME=$$(basename $$0) -REL=$${FILENAME%.*} - -tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR - -$$TMPDIR/bin/$$REL console -RET=$$? - -rm -rf $$TMPDIR - -exit $$RET - -__ARCHIVE_BELOW__ -endef - -sfx: - $(call render_template,sfx_stub,$(SFX_OUTPUT_FILE)) - $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) - $(verbose) chmod +x $(SFX_OUTPUT_FILE) - -endif -endif - -# Copyright (c) 2013-2017, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# External plugins. - -DEP_PLUGINS ?= - -$(foreach p,$(DEP_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/plugins.mk,$p)))) - # Copyright (c) 2013-2015, Loïc Hoguin # Copyright (c) 2015-2016, Jean-Sébastien Pédron # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6905,20 +6698,22 @@ ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep $@ \ IS_APP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ done endif - $(verbose) set -e; for dep in $^ ; do \ + $(verbose) for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ - if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ $(MAKE) -C $$dep fetch-deps \ IS_DEP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ fi \ fi \ done diff --git a/rabbitmq-server/deps/rabbit_common/include/old_builtin_types.hrl b/deps/rabbit_common/include/old_builtin_types.hrl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/include/old_builtin_types.hrl rename to deps/rabbit_common/include/old_builtin_types.hrl diff --git a/rabbitmq-server/deps/rabbit_common/include/rabbit.hrl b/deps/rabbit_common/include/rabbit.hrl similarity index 93% rename from rabbitmq-server/deps/rabbit_common/include/rabbit.hrl rename to deps/rabbit_common/include/rabbit.hrl index 6c75284..a514390 100644 --- a/rabbitmq-server/deps/rabbit_common/include/rabbit.hrl +++ b/deps/rabbit_common/include/rabbit.hrl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is Pivotal Software, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. %% -include("old_builtin_types.hrl"). @@ -98,7 +98,7 @@ -record(trie_edge, {exchange_name, node_id, word}). -record(trie_binding, {exchange_name, node_id, destination, arguments}). --record(listener, {node, protocol, host, ip_address, port, opts = []}). +-record(listener, {node, protocol, host, ip_address, port}). -record(runtime_parameters, {key, value}). @@ -132,7 +132,7 @@ %%---------------------------------------------------------------------------- --define(COPYRIGHT_MESSAGE, "Copyright (C) 2007-2017 Pivotal Software, Inc."). +-define(COPYRIGHT_MESSAGE, "Copyright (C) 2007-2016 Pivotal Software, Inc."). -define(INFORMATION_MESSAGE, "Licensed under the MPL. See http://www.rabbitmq.com/"). -define(OTP_MINIMUM, "R16B03"). -define(ERTS_MINIMUM, "5.10.4"). @@ -147,18 +147,16 @@ -define(EMPTY_FRAME_SIZE, 8). -define(MAX_WAIT, 16#ffffffff). --define(SUPERVISOR_WAIT, - rabbit_misc:get_env(rabbit, supervisor_shutdown_timeout, infinity)). --define(WORKER_WAIT, - rabbit_misc:get_env(rabbit, worker_shutdown_timeout, 30000)). +-define(SUPERVISOR_WAIT, infinity). +-define(WORKER_WAIT, 30000). -define(HIBERNATE_AFTER_MIN, 1000). -define(DESIRED_HIBERNATE, 10000). --define(CREDIT_DISC_BOUND, {4000, 800}). +-define(CREDIT_DISC_BOUND, {2000, 500}). %% When we discover that we should write some indices to disk for some %% betas, the IO_BATCH_SIZE sets the number of betas that we must be %% due to write indices for before we do any work at all. --define(IO_BATCH_SIZE, 4096). %% next power-of-2 after ?CREDIT_DISC_BOUND +-define(IO_BATCH_SIZE, 2048). %% next power-of-2 after ?CREDIT_DISC_BOUND -define(INVALID_HEADERS_KEY, <<"x-invalid-headers">>). -define(ROUTING_HEADERS, [<<"CC">>, <<"BCC">>]). diff --git a/rabbitmq-server/deps/rabbit_common/include/rabbit_misc.hrl b/deps/rabbit_common/include/rabbit_misc.hrl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/include/rabbit_misc.hrl rename to deps/rabbit_common/include/rabbit_misc.hrl diff --git a/rabbitmq-server/deps/rabbit_common/include/rabbit_msg_store.hrl b/deps/rabbit_common/include/rabbit_msg_store.hrl similarity index 91% rename from rabbitmq-server/deps/rabbit_common/include/rabbit_msg_store.hrl rename to deps/rabbit_common/include/rabbit_msg_store.hrl index 82b866e..8cf830c 100644 --- a/rabbitmq-server/deps/rabbit_common/include/rabbit_msg_store.hrl +++ b/deps/rabbit_common/include/rabbit_msg_store.hrl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is Pivotal Software, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2015 Pivotal Software, Inc. All rights reserved. %% -include("rabbit.hrl"). diff --git a/deps/rabbit_common/mk/rabbitmq-build.mk b/deps/rabbit_common/mk/rabbitmq-build.mk new file mode 100644 index 0000000..52b3ed3 --- /dev/null +++ b/deps/rabbit_common/mk/rabbitmq-build.mk @@ -0,0 +1,70 @@ +# -------------------------------------------------------------------- +# Compiler flags. +# -------------------------------------------------------------------- + +# FIXME: We copy Erlang.mk default flags here: rabbitmq-build.mk is +# loaded as a plugin, so before those variables are defined. And because +# Erlang.mk uses '?=', the flags we set here override the default set. +# +# See: https://github.com/ninenines/erlang.mk/issues/502 + +WARNING_OPTS += +debug_info \ + +warn_export_vars \ + +warn_shadow_vars \ + +warn_obsolete_guard +ERLC_OPTS += -Werror $(WARNING_OPTS) +TEST_ERLC_OPTS += $(WARNING_OPTS) + +define compare_version +$(shell awk 'BEGIN { + split("$(1)", v1, "."); + version1 = v1[1] * 1000000 + v1[2] * 10000 + v1[3] * 100 + v1[4]; + + split("$(2)", v2, "."); + version2 = v2[1] * 1000000 + v2[2] * 10000 + v2[3] * 100 + v2[4]; + + if (version1 $(3) version2) { + print "true"; + } else { + print "false"; + } +}') +endef + +# Erlang R16B03 has no support for new types in Erlang 17.0, leading to +# a build-time error. +ERTS_VER := $(shell erl -version 2>&1 | sed -E 's/.* version //') +old_builtin_types_MAX_ERTS_VER = 6.0 +ifeq ($(call compare_version,$(ERTS_VER),$(old_builtin_types_MAX_ERTS_VER),<),true) +RMQ_ERLC_OPTS += -Duse_old_builtin_types +endif + +# Push our compilation options to both the normal and test ERLC_OPTS. +ERLC_OPTS += $(RMQ_ERLC_OPTS) +TEST_ERLC_OPTS += $(RMQ_ERLC_OPTS) + +# -------------------------------------------------------------------- +# Common test flags. +# -------------------------------------------------------------------- + +# Disable most messages on Travis and Concourse. +# +# Concourse doesn't set any environment variables to help us automate +# things. In rabbitmq-ci, we run tests under the `concourse` user so, +# look at that... +CT_QUIET_FLAGS = -verbosity 50 \ + -erl_args \ + -kernel error_logger silent +ifdef TRAVIS +CT_OPTS += $(CT_QUIET_FLAGS) +endif +ifdef CONCOURSE +CT_OPTS += $(CT_QUIET_FLAGS) +endif + +# Enable JUnit-like report on Jenkins. Jenkins parses those reports so +# the results can be browsed from its UI. Furthermore, it displays a +# graph showing evolution of the results over time. +ifdef JENKINS_HOME +CT_OPTS += -ct_hooks cth_surefire +endif diff --git a/rabbitmq-server/deps/amqp_client/rabbitmq-components.mk b/deps/rabbit_common/mk/rabbitmq-components.mk similarity index 83% rename from rabbitmq-server/deps/amqp_client/rabbitmq-components.mk rename to deps/rabbit_common/mk/rabbitmq-components.mk index 1e5d000..05986d8 100644 --- a/rabbitmq-server/deps/amqp_client/rabbitmq-components.mk +++ b/deps/rabbit_common/mk/rabbitmq-components.mk @@ -5,27 +5,6 @@ ifeq ($(.DEFAULT_GOAL),) .DEFAULT_GOAL = all endif -# PROJECT_VERSION defaults to: -# 1. the version exported by rabbitmq-server-release; -# 2. the version stored in `git-revisions.txt`, if it exists; -# 3. a version based on git-describe(1), if it is a Git clone; -# 4. 0.0.0 - -PROJECT_VERSION := $(RABBITMQ_VERSION) - -ifeq ($(PROJECT_VERSION),) -PROJECT_VERSION := $(shell \ -if test -f git-revisions.txt; then \ - head -n1 git-revisions.txt | \ - awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ -else \ - (git describe --dirty --abbrev=7 --tags --always --first-parent \ - 2>/dev/null || echo rabbitmq_v0_0_0) | \ - sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ - -e 's/-/./g'; \ -fi) -endif - # -------------------------------------------------------------------- # RabbitMQ components. # -------------------------------------------------------------------- @@ -42,17 +21,13 @@ dep_rabbit = git_rmq rabbitmq-server $(current_rmq_re dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master @@ -61,7 +36,6 @@ dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rm dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master @@ -73,11 +47,6 @@ dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(cur dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master @@ -97,41 +66,30 @@ dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(cu dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master -# Third-party dependencies version pinning. -# -# We do that in this file, which is copied in all projects, to ensure -# all projects use the same versions. It avoids conflicts and makes it -# possible to work with rabbitmq-public-umbrella. - -dep_cowboy_commit = 1.0.4 -dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2 -# Last commit of PropEr supporting Erlang R16B03. -dep_proper_commit = 735d972758d8bd85b12483626fe1b66450d6a6fe -dep_ranch_commit = 1.3.2 -# Last commit of sockjs support Erlang R16B03 and 17.x. -dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 5af2b588c812c318b19bc105b577a759c71c3e0a -dep_webmachine_commit = 1.10.8p2 +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 RABBITMQ_COMPONENTS = amqp_client \ rabbit \ rabbit_common \ rabbitmq_amqp1_0 \ rabbitmq_auth_backend_amqp \ - rabbitmq_auth_backend_cache \ rabbitmq_auth_backend_http \ rabbitmq_auth_backend_ldap \ rabbitmq_auth_mechanism_ssl \ - rabbitmq_aws \ rabbitmq_boot_steps_visualiser \ rabbitmq_clusterer \ - rabbitmq_cli \ rabbitmq_codegen \ rabbitmq_consistent_hash_exchange \ - rabbitmq_ct_client_helpers \ rabbitmq_ct_helpers \ rabbitmq_delayed_message_exchange \ rabbitmq_dotnet_client \ @@ -140,7 +98,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_federation_management \ rabbitmq_java_client \ rabbitmq_jms_client \ - rabbitmq_jms_cts \ rabbitmq_jms_topic_exchange \ rabbitmq_lvc \ rabbitmq_management \ @@ -152,11 +109,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_metronome \ rabbitmq_mqtt \ rabbitmq_objc_client \ - rabbitmq_peer_discovery_aws \ - rabbitmq_peer_discovery_common \ - rabbitmq_peer_discovery_consul \ - rabbitmq_peer_discovery_etcd \ - rabbitmq_peer_discovery_k8s \ rabbitmq_recent_history_exchange \ rabbitmq_routing_node_stamp \ rabbitmq_rtopic_exchange \ diff --git a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-dist.mk b/deps/rabbit_common/mk/rabbitmq-dist.mk similarity index 100% rename from rabbitmq-server/deps/rabbit_common/mk/rabbitmq-dist.mk rename to deps/rabbit_common/mk/rabbitmq-dist.mk diff --git a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-plugin.mk b/deps/rabbit_common/mk/rabbitmq-plugin.mk similarity index 66% rename from rabbitmq-server/deps/rabbit_common/mk/rabbitmq-plugin.mk rename to deps/rabbit_common/mk/rabbitmq-plugin.mk index 29064a9..2e0db8e 100644 --- a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-plugin.mk +++ b/deps/rabbit_common/mk/rabbitmq-plugin.mk @@ -2,10 +2,6 @@ ifeq ($(filter rabbitmq-build.mk,$(notdir $(MAKEFILE_LIST))),) include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-build.mk endif -ifeq ($(filter rabbitmq-hexpm.mk,$(notdir $(MAKEFILE_LIST))),) -include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-hexpm.mk -endif - ifeq ($(filter rabbitmq-dist.mk,$(notdir $(MAKEFILE_LIST))),) include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-dist.mk endif @@ -14,10 +10,6 @@ ifeq ($(filter rabbitmq-run.mk,$(notdir $(MAKEFILE_LIST))),) include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-run.mk endif -ifeq ($(filter rabbitmq-test.mk,$(notdir $(MAKEFILE_LIST))),) -include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-test.mk -endif - ifeq ($(filter rabbitmq-tools.mk,$(notdir $(MAKEFILE_LIST))),) include $(dir $(lastword $(MAKEFILE_LIST)))rabbitmq-tools.mk endif diff --git a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-run.mk b/deps/rabbit_common/mk/rabbitmq-run.mk similarity index 95% rename from rabbitmq-server/deps/rabbit_common/mk/rabbitmq-run.mk rename to deps/rabbit_common/mk/rabbitmq-run.mk index a79cb91..5bf78b3 100644 --- a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-run.mk +++ b/deps/rabbit_common/mk/rabbitmq-run.mk @@ -165,20 +165,7 @@ define test_rabbitmq_config_with_tls {verify, verify_peer}, {fail_if_no_peer_cert, false}, {honor_cipher_order, true}]} - ]}, - {rabbitmq_management, [ - {listener, [ - {port, 15671}, - {ssl, true}, - {ssl_opts, [ - {cacertfile, "$(TEST_TLS_CERTS_DIR_in_config)/testca/cacert.pem"}, - {certfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/cert.pem"}, - {keyfile, "$(TEST_TLS_CERTS_DIR_in_config)/server/key.pem"}, - {verify, verify_peer}, - {fail_if_no_peer_cert, false}, - {honor_cipher_order, true}]} - ]} - ]} + ]} ]. endef diff --git a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-tools.mk b/deps/rabbit_common/mk/rabbitmq-tools.mk similarity index 100% rename from rabbitmq-server/deps/rabbit_common/mk/rabbitmq-tools.mk rename to deps/rabbit_common/mk/rabbitmq-tools.mk diff --git a/rabbitmq-server/deps/rabbit_common/src/app_utils.erl b/deps/rabbit_common/src/app_utils.erl similarity index 94% rename from rabbitmq-server/deps/rabbit_common/src/app_utils.erl rename to deps/rabbit_common/src/app_utils.erl index 0ae5376..6504c3f 100644 --- a/rabbitmq-server/deps/rabbit_common/src/app_utils.erl +++ b/deps/rabbit_common/src/app_utils.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(app_utils). @@ -58,10 +58,7 @@ start_applications(Apps, ErrorHandler) -> stop_applications(Apps, ErrorHandler) -> manage_applications(fun lists:foldr/3, - fun(App) -> - rabbit_log:info("Stopping application '~s'", [App]), - application:stop(App) - end, + fun application:stop/1, fun application:start/1, not_started, ErrorHandler, diff --git a/rabbitmq-server/deps/rabbit_common/src/code_version.erl b/deps/rabbit_common/src/code_version.erl similarity index 93% rename from rabbitmq-server/deps/rabbit_common/src/code_version.erl rename to deps/rabbit_common/src/code_version.erl index 0c0fe5b..c6657d8 100644 --- a/rabbitmq-server/deps/rabbit_common/src/code_version.erl +++ b/deps/rabbit_common/src/code_version.erl @@ -11,11 +11,11 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(code_version). --export([update/1, get_otp_version/0]). +-export([update/1]). %%---------------------------------------------------------------------------- %% API @@ -54,15 +54,6 @@ %% %% See `time_compat.erl` for an example. %% -%% CAUTION: Make sure that all functions in the module are patched this -%% way! If you have "regular" functions, you might hit a race condition -%% between the unload of the old module and the load of the patched -%% module. If all functions are patched, loading will be serialized, -%% thanks to a lock acquired by `code_version`. However, if you have -%% regular functions, any call to them will bypass that lock and the old -%% code will be reloaded from disk. This will kill the process trying to -%% patch the module. -%% %% end %%---------------------------------------------------------------------------- -spec update(atom()) -> ok | no_return(). diff --git a/rabbitmq-server/deps/rabbit_common/src/credit_flow.erl b/deps/rabbit_common/src/credit_flow.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/credit_flow.erl rename to deps/rabbit_common/src/credit_flow.erl index acbeb25..e9b16f4 100644 --- a/rabbitmq-server/deps/rabbit_common/src/credit_flow.erl +++ b/deps/rabbit_common/src/credit_flow.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(credit_flow). diff --git a/rabbitmq-server/deps/rabbit_common/src/ec_semver.erl b/deps/rabbit_common/src/ec_semver.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/ec_semver.erl rename to deps/rabbit_common/src/ec_semver.erl index d08ebca..6ae5597 100644 --- a/rabbitmq-server/deps/rabbit_common/src/ec_semver.erl +++ b/deps/rabbit_common/src/ec_semver.erl @@ -1,9 +1,8 @@ %%% vi:ts=4 sw=4 et %%% Imported from https://github.com/erlware/erlware_commons.git -%%% Commit 09168347525916e291c8aa6e3073e260e5f4a116 -%%% - We export normalize/1. -%%% - We add a few more testcases around string/binary comparison. +%%% Commit 603441a0363d5433de2139759991c640846c3a62 +%%% We export normalize/1 here %%%------------------------------------------------------------------- %%% @copyright (C) 2011, Erlware LLC @@ -373,6 +372,7 @@ eql_test() -> ?assertMatch(true, not eql("FFF", "BBB")), ?assertMatch(true, not eql("1", "1BBBB")). + gt_test() -> ?assertMatch(true, gt("1.0.0-alpha.1", "1.0.0-alpha")), diff --git a/rabbitmq-server/deps/rabbit_common/src/ec_semver_parser.erl b/deps/rabbit_common/src/ec_semver_parser.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/ec_semver_parser.erl rename to deps/rabbit_common/src/ec_semver_parser.erl index 584ebbc..ad95fe5 100644 --- a/rabbitmq-server/deps/rabbit_common/src/ec_semver_parser.erl +++ b/deps/rabbit_common/src/ec_semver_parser.erl @@ -1,5 +1,5 @@ %%% Imported from https://github.com/erlware/erlware_commons.git -%%% Commit 09168347525916e291c8aa6e3073e260e5f4a116 +%%% Commit 603441a0363d5433de2139759991c640846c3a62 -module(ec_semver_parser). -export([parse/1,file/1]). @@ -15,7 +15,7 @@ -define(p_zero_or_more,true). - +-compile(export_all). -spec file(file:name()) -> any(). file(Filename) -> case file:read_file(Filename) of {ok,Bin} -> parse(Bin); Err -> Err end. diff --git a/rabbitmq-server/deps/rabbit_common/src/gen_server2.erl b/deps/rabbit_common/src/gen_server2.erl similarity index 93% rename from rabbitmq-server/deps/rabbit_common/src/gen_server2.erl rename to deps/rabbit_common/src/gen_server2.erl index ae1284c..e2265f7 100644 --- a/rabbitmq-server/deps/rabbit_common/src/gen_server2.erl +++ b/deps/rabbit_common/src/gen_server2.erl @@ -91,9 +91,8 @@ %% call/3, i.e. a pid, global name, local name, or local name on a %% particular node. %% -%% 11) Internal buffer length is emitted as a core [RabbitMQ] metric. -%% All modifications are (C) 2009-2017 Pivotal Software, Inc. +%% All modifications are (C) 2009-2013 GoPivotal, Inc. %% ``The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -219,8 +218,7 @@ %% State record -record(gs2_state, {parent, name, state, mod, time, - timeout_state, queue, debug, prioritisers, - timer, init_stats_fun, emit_stats_fun, stop_stats_fun}). + timeout_state, queue, debug, prioritisers}). %%%========================================================================= %%% Specs. These exist only to shut up dialyzer's warnings @@ -515,14 +513,10 @@ enter_loop(Mod, Options, State, ServerName, Timeout, Backoff) -> Debug = debug_options(Name, Options), Queue = priority_queue:new(), Backoff1 = extend_backoff(Backoff), - {InitStatsFun, EmitStatsFun, StopStatsFun} = stats_funs(), - loop(InitStatsFun(find_prioritisers( + loop(find_prioritisers( #gs2_state { parent = Parent, name = Name, state = State, mod = Mod, time = Timeout, timeout_state = Backoff1, - queue = Queue, debug = Debug, - init_stats_fun = InitStatsFun, - emit_stats_fun = EmitStatsFun, - stop_stats_fun = StopStatsFun }))). + queue = Queue, debug = Debug })). %%%======================================================================== %%% Gen-callback functions @@ -541,42 +535,37 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) -> Name = name(Name0), Debug = debug_options(Name, Options), Queue = priority_queue:new(), - {InitStatsFun, EmitStatsFun, StopStatsFun} = stats_funs(), GS2State = find_prioritisers( #gs2_state { parent = Parent, name = Name, mod = Mod, queue = Queue, - debug = Debug, - init_stats_fun = InitStatsFun, - emit_stats_fun = EmitStatsFun, - stop_stats_fun = StopStatsFun }), + debug = Debug }), case catch Mod:init(Args) of {ok, State} -> proc_lib:init_ack(Starter, {ok, self()}), - loop(InitStatsFun(GS2State#gs2_state { state = State, - time = infinity, - timeout_state = undefined })); + loop(GS2State #gs2_state { state = State, + time = infinity, + timeout_state = undefined }); {ok, State, Timeout} -> proc_lib:init_ack(Starter, {ok, self()}), - loop(InitStatsFun( - GS2State#gs2_state { state = State, - time = Timeout, - timeout_state = undefined })); + loop(GS2State #gs2_state { state = State, + time = Timeout, + timeout_state = undefined }); {ok, State, Timeout, Backoff = {backoff, _, _, _}} -> Backoff1 = extend_backoff(Backoff), proc_lib:init_ack(Starter, {ok, self()}), - loop(InitStatsFun(GS2State#gs2_state { state = State, - time = Timeout, - timeout_state = Backoff1 })); + loop(GS2State #gs2_state { state = State, + time = Timeout, + timeout_state = Backoff1 }); {ok, State, Timeout, Backoff = {backoff, _, _, _}, Mod1} -> Backoff1 = extend_backoff(Backoff), proc_lib:init_ack(Starter, {ok, self()}), - loop(InitStatsFun(find_prioritisers( - GS2State#gs2_state { mod = Mod1, - state = State, - time = Timeout, - timeout_state = Backoff1 }))); + loop(find_prioritisers( + GS2State #gs2_state { mod = Mod1, + state = State, + time = Timeout, + timeout_state = Backoff1 })); {stop, Reason} -> %% For consistency, we must make sure that the %% registered name (if any) is unregistered before @@ -708,9 +697,8 @@ hibernate(GS2State = #gs2_state { timeout_state = TimeoutState }) -> proc_lib:hibernate(?MODULE, wake_hib, [GS2State #gs2_state { timeout_state = TS }]). -pre_hibernate(GS2State0 = #gs2_state { state = State, - mod = Mod }) -> - GS2State = maybe_stop_stats(GS2State0), +pre_hibernate(GS2State = #gs2_state { state = State, + mod = Mod }) -> case erlang:function_exported(Mod, handle_pre_hibernate, 1) of true -> case catch Mod:handle_pre_hibernate(State) of @@ -723,10 +711,8 @@ pre_hibernate(GS2State0 = #gs2_state { state = State, hibernate(GS2State) end. -post_hibernate(GS2State0 = #gs2_state { state = State, - mod = Mod, - init_stats_fun = InitStatsFun }) -> - GS2State = InitStatsFun(GS2State0), +post_hibernate(GS2State = #gs2_state { state = State, + mod = Mod }) -> case erlang:function_exported(Mod, handle_post_hibernate, 1) of true -> case catch Mod:handle_post_hibernate(State) of @@ -780,8 +766,6 @@ in({'EXIT', Parent, _R} = Input, GS2State = #gs2_state { parent = Parent }) -> in(Input, infinity, GS2State); in({system, _From, _Req} = Input, GS2State) -> in(Input, infinity, GS2State); -in(emit_gen_server2_stats, GS2State = #gs2_state{ emit_stats_fun = EmitStatsFun }) -> - EmitStatsFun(GS2State); in(Input, GS2State = #gs2_state { prioritisers = {_, _, F} }) -> in(Input, F(Input, GS2State), GS2State). @@ -1141,9 +1125,7 @@ print_event(Dev, Event, Name) -> terminate(Reason, Msg, #gs2_state { name = Name, mod = Mod, state = State, - debug = Debug, - stop_stats_fun = StopStatsFun} = GS2State) -> - StopStatsFun(GS2State), + debug = Debug }) -> case catch Mod:terminate(Reason, State) of {'EXIT', R} -> error_info(R, Reason, Name, Msg, State, Debug), @@ -1363,31 +1345,3 @@ callback(Mod, FunName, Args, DefaultThunk) -> end; false -> DefaultThunk() end. - -stats_funs() -> - case ets:info(gen_server2_metrics) of - undefined -> - {fun(GS2State) -> GS2State end, - fun(GS2State) -> GS2State end, - fun(GS2State) -> GS2State end}; - _ -> - {fun init_stats/1, fun emit_stats/1, fun stop_stats/1} - end. - -init_stats(GS2State) -> - emit_stats(rabbit_event:init_stats_timer(GS2State, #gs2_state.timer)). - -emit_stats(GS2State = #gs2_state{queue = Queue}) -> - rabbit_core_metrics:gen_server2_stats(self(), priority_queue:len(Queue)), - rabbit_event:ensure_stats_timer( - rabbit_event:reset_stats_timer(GS2State, #gs2_state.timer), - #gs2_state.timer, emit_gen_server2_stats). - -stop_stats(GS2State) -> - maybe_stop_stats(GS2State), - rabbit_core_metrics:gen_server2_deleted(self()). - -maybe_stop_stats(#gs2_state{timer = undefined} = GS2State) -> - GS2State; -maybe_stop_stats(GS2State) -> - rabbit_event:stop_stats_timer(GS2State, #gs2_state.timer). diff --git a/rabbitmq-server/deps/rabbit_common/src/mirrored_supervisor.erl b/deps/rabbit_common/src/mirrored_supervisor.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/mirrored_supervisor.erl rename to deps/rabbit_common/src/mirrored_supervisor.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/mochijson2.erl b/deps/rabbit_common/src/mochijson2.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/mochijson2.erl rename to deps/rabbit_common/src/mochijson2.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/mochinum.erl b/deps/rabbit_common/src/mochinum.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/mochinum.erl rename to deps/rabbit_common/src/mochinum.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/pmon.erl b/deps/rabbit_common/src/pmon.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/pmon.erl rename to deps/rabbit_common/src/pmon.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/priority_queue.erl b/deps/rabbit_common/src/priority_queue.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/priority_queue.erl rename to deps/rabbit_common/src/priority_queue.erl index 70c059f..8196947 100644 --- a/rabbitmq-server/deps/rabbit_common/src/priority_queue.erl +++ b/deps/rabbit_common/src/priority_queue.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% Priority queues have essentially the same interface as ordinary diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue.erl b/deps/rabbit_common/src/rabbit_amqqueue.erl similarity index 92% rename from rabbitmq-server/deps/rabbit/src/rabbit_amqqueue.erl rename to deps/rabbit_common/src/rabbit_amqqueue.erl index 467cd99..64dc338 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_amqqueue.erl +++ b/deps/rabbit_common/src/rabbit_amqqueue.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqqueue). @@ -25,7 +25,7 @@ check_exclusive_access/2, with_exclusive_access_or_die/3, stat/1, deliver/2, requeue/3, ack/3, reject/4]). -export([list/0, list/1, info_keys/0, info/1, info/2, info_all/1, info_all/2, - info_all/5, info_local/1, list_names/0, list_local_names/0]). + info_all/5, info_local/1]). -export([list_down/1]). -export([force_event_refresh/1, notify_policy_changed/1]). -export([consumers/1, consumers_all/1, consumers_all/3, consumer_info_keys/0]). @@ -34,8 +34,7 @@ -export([notify_down_all/2, notify_down_all/3, activate_limit_all/2, credit/5]). -export([on_node_up/1, on_node_down/1]). -export([update/2, store_queue/1, update_decorators/1, policy_changed/2]). --export([update_mirroring/1, sync_mirrors/1, cancel_sync_mirrors/1]). --export([is_mirrored/1, is_dead_exclusive/1]). % Note: exported due to use in qlc expression. +-export([update_mirroring/1, sync_mirrors/1, cancel_sync_mirrors/1, is_mirrored/1]). -export([pid_of/1, pid_of/2]). @@ -109,7 +108,6 @@ A | rabbit_types:channel_exit(). -spec list() -> [rabbit_types:amqqueue()]. -spec list(rabbit_types:vhost()) -> [rabbit_types:amqqueue()]. --spec list_names() -> [rabbit_amqqueue:name()]. -spec list_down(rabbit_types:vhost()) -> [rabbit_types:amqqueue()]. -spec info_keys() -> rabbit_types:info_keys(). -spec info(rabbit_types:amqqueue()) -> rabbit_types:infos(). @@ -174,6 +172,8 @@ -spec basic_cancel (rabbit_types:amqqueue(), pid(), rabbit_types:ctag(), any()) -> 'ok'. -spec notify_decorators(rabbit_types:amqqueue()) -> 'ok'. +-spec notify_sent(pid(), pid()) -> 'ok'. +-spec notify_sent_queue_down(pid()) -> 'ok'. -spec resume(pid(), pid()) -> 'ok'. -spec internal_delete(name()) -> rabbit_types:ok_or_error('not_found') | @@ -216,8 +216,7 @@ recover() -> %% Clear out remnants of old incarnation, in case we restarted %% faster than other nodes handled DOWN messages from us. on_node_down(node()), - DurableQueues = queues_to_recover(), - + DurableQueues = find_durable_queues(), L = length(DurableQueues), %% if there are not enough file handles, the server might hang @@ -259,30 +258,6 @@ start(Qs) -> [Pid ! {self(), go} || #amqqueue{pid = Pid} <- Qs], ok. -queues_to_recover() -> - DurableQueues = find_durable_queues(), - VHosts = rabbit_vhost:list(), - - {QueuesWithVhost, QueuesWithoutVhost} = lists:partition( - fun(#amqqueue{name = #resource{virtual_host = VHost}}) -> - lists:member(VHost, VHosts) - end, - DurableQueues), - - {LocalQueuesWithoutVhost, _RemoteQueuesWithoutVhost} = lists:partition( - fun(#amqqueue{pid = QPid}) -> node(QPid) == node() end, - QueuesWithoutVhost), - - {atomic, ok} = - mnesia:sync_transaction( - fun () -> - [ internal_delete1(Name, false) - || #amqqueue{name = Name} <- LocalQueuesWithoutVhost ], - ok - end), - - QueuesWithVhost. - find_durable_queues() -> Node = node(), mnesia:async_dirty( @@ -291,12 +266,12 @@ find_durable_queues() -> pid = Pid} <- mnesia:table(rabbit_durable_queue), node(Pid) == Node andalso - %% Terminations on node down will not remove the rabbit_queue - %% record if it is a mirrored queue (such info is now obtained from - %% the policy). Thus, we must check if the local pid is alive - %% - if the record is present - in order to restart. - (mnesia:read(rabbit_queue, Name, read) =:= [] - orelse not erlang:is_process_alive(Pid))])) + %% Terminations on node down will not remove the rabbit_queue + %% record if it is a mirrored queue (such info is now obtained from + %% the policy). Thus, we must check if the local pid is alive + %% - if the record is present - in order to restart. + (mnesia:read(rabbit_queue, Name, read) =:= [] + orelse not erlang:is_process_alive(Pid))])) end). recover_durable_queues(QueuesAndRecoveryTerms) -> @@ -595,15 +570,7 @@ check_queue_mode({Type, _}, _Args) -> list() -> mnesia:dirty_match_object(rabbit_queue, #amqqueue{_ = '_'}). -list_names() -> mnesia:dirty_all_keys(rabbit_queue). - -list_local_names() -> - [ Q#amqqueue.name || #amqqueue{state = State, pid = QPid} = Q <- list(), - State =/= crashed, - node() =:= node(QPid) ]. - -list(VHostPath) -> - list(VHostPath, rabbit_queue). +list(VHostPath) -> list(VHostPath, rabbit_queue). %% Not dirty_match_object since that would not be transactional when used in a %% tx context @@ -617,16 +584,12 @@ list(VHostPath, TableName) -> end). list_down(VHostPath) -> - case rabbit_vhost:exists(VHostPath) of - false -> []; - true -> - Present = list(VHostPath), - Durable = list(VHostPath, rabbit_durable_queue), - PresentS = sets:from_list([N || #amqqueue{name = N} <- Present]), - sets:to_list(sets:filter(fun (#amqqueue{name = N}) -> - not sets:is_element(N, PresentS) - end, sets:from_list(Durable))) - end. + Present = list(VHostPath), + Durable = list(VHostPath, rabbit_durable_queue), + PresentS = sets:from_list([N || #amqqueue{name = N} <- Present]), + sets:to_list(sets:filter(fun (#amqqueue{name = N}) -> + not sets:is_element(N, PresentS) + end, sets:from_list(Durable))). info_keys() -> rabbit_amqqueue_process:info_keys(). @@ -810,10 +773,21 @@ notify_decorators(#amqqueue{pid = QPid}) -> delegate:cast(QPid, notify_decorators). notify_sent(QPid, ChPid) -> - rabbit_amqqueue_common:notify_sent(QPid, ChPid). + Key = {consumer_credit_to, QPid}, + put(Key, case get(Key) of + 1 -> gen_server2:cast( + QPid, {notify_sent, ChPid, + ?MORE_CONSUMER_CREDIT_AFTER}), + ?MORE_CONSUMER_CREDIT_AFTER; + undefined -> erlang:monitor(process, QPid), + ?MORE_CONSUMER_CREDIT_AFTER - 1; + C -> C - 1 + end), + ok. notify_sent_queue_down(QPid) -> - rabbit_amqqueue_common:notify_sent_queue_down(QPid). + erase({consumer_credit_to, QPid}), + ok. resume(QPid, ChPid) -> delegate:cast(QPid, {resume, ChPid}). @@ -841,7 +815,6 @@ internal_delete(QueueName) -> T = rabbit_binding:process_deletions(Deletions), fun() -> ok = T(), - rabbit_core_metrics:queue_deleted(QueueName), ok = rabbit_event:notify(queue_deleted, [{name, QueueName}]) end @@ -889,10 +862,8 @@ forget_node_for_queue(DeadNode, [H|T], Q) -> node_permits_offline_promotion(Node) -> case node() of Node -> not rabbit:is_running(); %% [1] - _ -> All = rabbit_mnesia:cluster_nodes(all), - Running = rabbit_mnesia:cluster_nodes(running), - lists:member(Node, All) andalso - not lists:member(Node, Running) %% [2] + _ -> Running = rabbit_mnesia:cluster_nodes(running), + not lists:member(Node, Running) %% [2] end. %% [1] In this case if we are a real running node (i.e. rabbitmqctl %% has RPCed into us) then we cannot allow promotion. If on the other @@ -920,11 +891,6 @@ cancel_sync_mirrors(QPid) -> delegate:call(QPid, cancel_sync_mi is_mirrored(Q) -> rabbit_mirror_queue_misc:is_mirrored(Q). -is_dead_exclusive(#amqqueue{exclusive_owner = none}) -> - false; -is_dead_exclusive(#amqqueue{exclusive_owner = Pid}) when is_pid(Pid) -> - not rabbit_mnesia:is_process_alive(Pid). - on_node_up(Node) -> ok = rabbit_misc:execute_mnesia_transaction( fun () -> @@ -969,12 +935,11 @@ on_node_down(Node) -> rabbit_misc:execute_mnesia_tx_with_tail( fun () -> QsDels = qlc:e(qlc:q([{QName, delete_queue(QName)} || - #amqqueue{name = QName, pid = Pid} = - Q <- mnesia:table(rabbit_queue), - node(Pid) == Node andalso - not rabbit_mnesia:is_process_alive(Pid) andalso - (not rabbit_amqqueue:is_mirrored(Q) orelse - rabbit_amqqueue:is_dead_exclusive(Q))])), + #amqqueue{name = QName, pid = Pid} = Q + <- mnesia:table(rabbit_queue), + not rabbit_amqqueue:is_mirrored(Q) andalso + node(Pid) == Node andalso + not rabbit_mnesia:is_process_alive(Pid)])), {Qs, Dels} = lists:unzip(QsDels), T = rabbit_binding:process_deletions( lists:foldl(fun rabbit_binding:combine_deletions/2, @@ -983,7 +948,6 @@ on_node_down(Node) -> T(), lists:foreach( fun(QName) -> - rabbit_core_metrics:queue_deleted(QName), ok = rabbit_event:notify(queue_deleted, [{name, QName}]) end, Qs) diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_auth_backend_dummy.erl b/deps/rabbit_common/src/rabbit_auth_backend_dummy.erl similarity index 96% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_auth_backend_dummy.erl rename to deps/rabbit_common/src/rabbit_auth_backend_dummy.erl index 5891148..8ac1929 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_auth_backend_dummy.erl +++ b/deps/rabbit_common/src/rabbit_auth_backend_dummy.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_backend_dummy). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_auth_backend_internal.erl b/deps/rabbit_common/src/rabbit_auth_backend_internal.erl similarity index 94% rename from rabbitmq-server/deps/rabbit/src/rabbit_auth_backend_internal.erl rename to deps/rabbit_common/src/rabbit_auth_backend_internal.erl index 4933bd1..fdd954a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_auth_backend_internal.erl +++ b/deps/rabbit_common/src/rabbit_auth_backend_internal.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_backend_internal). @@ -26,8 +26,7 @@ -export([add_user/2, delete_user/1, lookup_user/1, change_password/2, clear_password/1, hash_password/2, change_password_hash/2, change_password_hash/3, - set_tags/2, set_permissions/5, clear_permissions/2, - add_user_sans_validation/2]). + set_tags/2, set_permissions/5, clear_permissions/2]). -export([user_info_keys/0, perms_info_keys/0, user_perms_info_keys/0, vhost_perms_info_keys/0, user_vhost_perms_info_keys/0, @@ -43,7 +42,7 @@ -type regexp() :: binary(). --spec add_user(rabbit_types:username(), rabbit_types:password()) -> 'ok' | {'error', string()}. +-spec add_user(rabbit_types:username(), rabbit_types:password()) -> 'ok'. -spec delete_user(rabbit_types:username()) -> 'ok'. -spec lookup_user (rabbit_types:username()) -> @@ -166,22 +165,7 @@ permission_index(read) -> #permission.read. %%---------------------------------------------------------------------------- %% Manipulation of the user database -validate_credentials(Username, Password) -> - rabbit_credential_validation:validate(Username, Password). - -validate_and_alternate_credentials(Username, Password, Fun) -> - case validate_credentials(Username, Password) of - ok -> - Fun(Username, Password); - {error, Err} -> - rabbit_log:error("Credential validation for '~s' failed!~n", [Username]), - {error, Err} - end. - add_user(Username, Password) -> - validate_and_alternate_credentials(Username, Password, fun add_user_sans_validation/2). - -add_user_sans_validation(Username, Password) -> rabbit_log:info("Creating user '~s'~n", [Username]), %% hash_password will pick the hashing function configured for us %% but we also need to store a hint as part of the record, so we @@ -228,9 +212,6 @@ lookup_user(Username) -> rabbit_misc:dirty_read({rabbit_user, Username}). change_password(Username, Password) -> - validate_and_alternate_credentials(Username, Password, fun change_password_sans_validation/2). - -change_password_sans_validation(Username, Password) -> rabbit_log:info("Changing password for '~s'~n", [Username]), HashingAlgorithm = rabbit_password:hashing_mod(), R = change_password_hash(Username, @@ -283,7 +264,7 @@ set_permissions(Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm) -> end end, [ConfigurePerm, WritePerm, ReadPerm]), R = rabbit_misc:execute_mnesia_transaction( - rabbit_vhost:with_user_and_vhost( + rabbit_misc:with_user_and_vhost( Username, VHostPath, fun () -> ok = mnesia:write( rabbit_user_permission, @@ -305,7 +286,7 @@ set_permissions(Username, VHostPath, ConfigurePerm, WritePerm, ReadPerm) -> clear_permissions(Username, VHostPath) -> R = rabbit_misc:execute_mnesia_transaction( - rabbit_vhost:with_user_and_vhost( + rabbit_misc:with_user_and_vhost( Username, VHostPath, fun () -> ok = mnesia:delete({rabbit_user_permission, @@ -390,7 +371,7 @@ list_vhost_permissions(VHostPath, Ref, AggregatorPid) -> list_user_vhost_permissions(Username, VHostPath) -> list_permissions( user_vhost_perms_info_keys(), - rabbit_vhost:with_user_and_vhost( + rabbit_misc:with_user_and_vhost( Username, VHostPath, match_user_vhost(Username, VHostPath))). extract_user_permission_params(Keys, #user_permission{ diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_auth_mechanism.erl b/deps/rabbit_common/src/rabbit_auth_mechanism.erl similarity index 96% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_auth_mechanism.erl rename to deps/rabbit_common/src/rabbit_auth_mechanism.erl index c84e156..4c41502 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_auth_mechanism.erl +++ b/deps/rabbit_common/src/rabbit_auth_mechanism.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_mechanism). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_authn_backend.erl b/deps/rabbit_common/src/rabbit_authn_backend.erl similarity index 95% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_authn_backend.erl rename to deps/rabbit_common/src/rabbit_authn_backend.erl index ad3818b..45f3c46 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_authn_backend.erl +++ b/deps/rabbit_common/src/rabbit_authn_backend.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_authn_backend). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_authz_backend.erl b/deps/rabbit_common/src/rabbit_authz_backend.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_authz_backend.erl rename to deps/rabbit_common/src/rabbit_authz_backend.erl index e256cb7..4315aaa 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_authz_backend.erl +++ b/deps/rabbit_common/src/rabbit_authz_backend.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_authz_backend). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_backing_queue.erl b/deps/rabbit_common/src/rabbit_backing_queue.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_backing_queue.erl rename to deps/rabbit_common/src/rabbit_backing_queue.erl index 9ddc761..bb4d03a 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_backing_queue.erl +++ b/deps/rabbit_common/src/rabbit_backing_queue.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_backing_queue). @@ -23,8 +23,7 @@ message_bytes, message_bytes_ready, message_bytes_unacknowledged, message_bytes_ram, message_bytes_persistent, head_message_timestamp, - disk_reads, disk_writes, backing_queue_status, - messages_paged_out, message_bytes_paged_out]). + disk_reads, disk_writes, backing_queue_status]). %% We can't specify a per-queue ack/state with callback signatures -type ack() :: any(). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_basic.erl b/deps/rabbit_common/src/rabbit_basic.erl similarity index 90% rename from rabbitmq-server/deps/rabbit/src/rabbit_basic.erl rename to deps/rabbit_common/src/rabbit_basic.erl index d474e9c..14f0a4e 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_basic.erl +++ b/deps/rabbit_common/src/rabbit_basic.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_basic). @@ -82,6 +82,12 @@ (rabbit_framing:amqp_property_record()) -> rabbit_types:ok_or_error2('undefined' | non_neg_integer(), any()). +-spec msg_size + (rabbit_types:content() | rabbit_types:message()) -> non_neg_integer(). + +-spec maybe_gc_large_msg + (rabbit_types:content() | rabbit_types:message()) -> non_neg_integer(). + %%---------------------------------------------------------------------------- %% Convenience function, for avoiding round-trips in calls across the @@ -295,8 +301,24 @@ parse_expiration(#'P_basic'{expiration = Expiration}) -> {error, {leftover_string, S}} end. +%% Some processes (channel, writer) can get huge amounts of binary +%% garbage when processing huge messages at high speed (since we only +%% do enough reductions to GC every few hundred messages, and if each +%% message is 1MB then that's ugly). So count how many bytes of +%% message we have processed, and force a GC every so often. maybe_gc_large_msg(Content) -> - rabbit_writer:maybe_gc_large_msg(Content). - -msg_size(Content) -> - rabbit_writer:msg_size(Content). + Size = msg_size(Content), + Current = case get(msg_size_for_gc) of + undefined -> 0; + C -> C + end, + New = Current + Size, + put(msg_size_for_gc, case New > 1000000 of + true -> erlang:garbage_collect(), + 0; + false -> New + end), + Size. + +msg_size(#content{payload_fragments_rev = PFR}) -> iolist_size(PFR); +msg_size(#basic_message{content = Content}) -> msg_size(Content). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_binary_generator.erl b/deps/rabbit_common/src/rabbit_binary_generator.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_binary_generator.erl rename to deps/rabbit_common/src/rabbit_binary_generator.erl index 5b0274e..95d06ff 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_binary_generator.erl +++ b/deps/rabbit_common/src/rabbit_binary_generator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_binary_generator). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_binary_parser.erl b/deps/rabbit_common/src/rabbit_binary_parser.erl similarity index 93% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_binary_parser.erl rename to deps/rabbit_common/src/rabbit_binary_parser.erl index 7c91e99..b84e120 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_binary_parser.erl +++ b/deps/rabbit_common/src/rabbit_binary_parser.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_binary_parser). @@ -68,12 +68,7 @@ parse_table(<<>>) -> ?SIMPLE_PARSE_TABLE($d, Value:64/float, double); ?SIMPLE_PARSE_TABLE($f, Value:32/float, float); -%% yes, both 'l' and 'L' fields are decoded to 64-bit signed values; -%% see https://github.com/rabbitmq/rabbitmq-server/issues/1093#issuecomment-276351183, -%% http://www.rabbitmq.com/amqp-0-9-1-errata.html, and section -%% 4.2.1 of the spec for details. ?SIMPLE_PARSE_TABLE($l, Value:64/signed, long); -?SIMPLE_PARSE_TABLE($L, Value:64/signed, long); parse_table(<>) -> ?SIMPLE_PARSE_ARRAY($f, Value:32/float, float); ?SIMPLE_PARSE_ARRAY($l, Value:64/signed, long); -?SIMPLE_PARSE_ARRAY($L, Value:64/signed, long); + parse_array(<<$t, Value:8/unsigned, Rest/binary>>) -> diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_channel.erl b/deps/rabbit_common/src/rabbit_channel.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_channel.erl rename to deps/rabbit_common/src/rabbit_channel.erl index dae0612..ef523a5 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_channel.erl +++ b/deps/rabbit_common/src/rabbit_channel.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_channel). @@ -150,8 +150,7 @@ -define(MAX_PERMISSION_CACHE_SIZE, 12). -define(STATISTICS_KEYS, - [reductions, - pid, + [pid, transactional, confirm, consumer_count, @@ -162,6 +161,7 @@ prefetch_count, global_prefetch_count, state, + reductions, garbage_collection]). -define(CREATION_EVENT_KEYS, @@ -391,9 +391,7 @@ init([Channel, ReaderPid, WriterPid, ConnPid, ConnName, Protocol, User, VHost, State1 = State#ch{ interceptor_state = rabbit_channel_interceptor:init(State)}, State2 = rabbit_event:init_stats_timer(State1, #ch.stats_timer), - Infos = infos(?CREATION_EVENT_KEYS, State2), - rabbit_core_metrics:channel_created(self(), Infos), - rabbit_event:notify(channel_created, Infos), + rabbit_event:notify(channel_created, infos(?CREATION_EVENT_KEYS, State2)), rabbit_event:if_enabled(State2, #ch.stats_timer, fun() -> emit_stats(State2) end), put(channel_operation_timeout, ?CHANNEL_OPERATION_TIMEOUT), @@ -617,13 +615,11 @@ handle_pre_hibernate(State) -> end), {hibernate, rabbit_event:stop_stats_timer(State, #ch.stats_timer)}. -terminate(_Reason, State = #ch{}) -> +terminate(_Reason, State) -> {_Res, _State1} = notify_queues(State), pg_local:leave(rabbit_channels, self()), rabbit_event:if_enabled(State, #ch.stats_timer, fun() -> emit_stats(State) end), - [delete_stats(Tag) || {Tag, _} <- get()], - rabbit_core_metrics:channel_closed(self()), rabbit_event:notify(channel_closed, [{pid, self()}]). code_change(_OldVsn, State, _Extra) -> @@ -660,7 +656,7 @@ send(Command, #ch{writer_pid = WriterPid}) -> ok = rabbit_writer:send_command(WriterPid, Command). format_soft_error(#amqp_error{name = N, explanation = E, method = M}) -> - io_lib:format("operation ~s caused a channel exception ~s: ~ts", [M, N, E]); + io_lib:format("operation ~s caused a channel exception ~s: ~p", [M, N, E]); format_soft_error(Reason) -> Reason. @@ -1998,37 +1994,43 @@ name(#ch{conn_name = ConnName, channel = Channel}) -> list_to_binary(rabbit_misc:format("~s (~p)", [ConnName, Channel])). incr_stats(Incs, Measure) -> - [begin - rabbit_core_metrics:channel_stats(Type, Measure, {self(), Key}, Inc), - %% Keys in the process dictionary are used to clean up the core metrics - put({Type, Key}, none) - end || {Type, Key, Inc} <- Incs]. + [update_measures(Type, Key, Inc, Measure) || {Type, Key, Inc} <- Incs]. + +update_measures(Type, Key, Inc, Measure) -> + Measures = case get({Type, Key}) of + undefined -> []; + D -> D + end, + Cur = case orddict:find(Measure, Measures) of + error -> 0; + {ok, C} -> C + end, + put({Type, Key}, orddict:store(Measure, Cur + Inc, Measures)). emit_stats(State) -> emit_stats(State, []). emit_stats(State, Extra) -> - [{reductions, Red} | Coarse0] = infos(?STATISTICS_KEYS, State), - rabbit_core_metrics:channel_stats(self(), Extra ++ Coarse0), - rabbit_core_metrics:channel_stats(reductions, self(), Red). + Coarse = infos(?STATISTICS_KEYS, State), + case rabbit_event:stats_level(State, #ch.stats_timer) of + coarse -> rabbit_event:notify(channel_stats, Extra ++ Coarse); + fine -> Fine = [{channel_queue_stats, + [{QName, Stats} || + {{queue_stats, QName}, Stats} <- get()]}, + {channel_exchange_stats, + [{XName, Stats} || + {{exchange_stats, XName}, Stats} <- get()]}, + {channel_queue_exchange_stats, + [{QX, Stats} || + {{queue_exchange_stats, QX}, Stats} <- get()]}], + rabbit_event:notify(channel_stats, Extra ++ Coarse ++ Fine) + end. erase_queue_stats(QName) -> - rabbit_core_metrics:channel_queue_down({self(), QName}), erase({queue_stats, QName}), - [begin - rabbit_core_metrics:channel_queue_exchange_down({self(), QX}), - erase({queue_exchange_stats, QX}) - end || {{queue_exchange_stats, QX = {QName0, _}}, _} <- get(), - QName0 =:= QName]. + [erase({queue_exchange_stats, QX}) || + {{queue_exchange_stats, QX = {QName0, _}}, _} <- get(), + QName0 =:= QName]. get_vhost(#ch{virtual_host = VHost}) -> VHost. get_user(#ch{user = User}) -> User. - -delete_stats({queue_stats, QName}) -> - rabbit_core_metrics:channel_queue_down({self(), QName}); -delete_stats({exchange_stats, XName}) -> - rabbit_core_metrics:channel_exchange_down({self(), XName}); -delete_stats({queue_exchange_stats, QX}) -> - rabbit_core_metrics:channel_queue_exchange_down({self(), QX}); -delete_stats(_) -> - ok. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_channel_interceptor.erl b/deps/rabbit_common/src/rabbit_channel_interceptor.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_channel_interceptor.erl rename to deps/rabbit_common/src/rabbit_channel_interceptor.erl index b237a5f..909bf4a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_channel_interceptor.erl +++ b/deps/rabbit_common/src/rabbit_channel_interceptor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_channel_interceptor). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_command_assembler.erl b/deps/rabbit_common/src/rabbit_command_assembler.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_command_assembler.erl rename to deps/rabbit_common/src/rabbit_command_assembler.erl index 5eec4ac..5adf7b1 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_command_assembler.erl +++ b/deps/rabbit_common/src/rabbit_command_assembler.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_command_assembler). diff --git a/deps/rabbit_common/src/rabbit_common.app.src b/deps/rabbit_common/src/rabbit_common.app.src new file mode 100644 index 0000000..3dbc2b7 --- /dev/null +++ b/deps/rabbit_common/src/rabbit_common.app.src @@ -0,0 +1,14 @@ +% vim:ft=erlang: + +{application, rabbit_common, [ + {description, ""}, + {vsn, "3.6.6"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib, + xmerl + ]} +]}. diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_control_misc.erl b/deps/rabbit_common/src/rabbit_control_misc.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_control_misc.erl rename to deps/rabbit_common/src/rabbit_control_misc.erl index ccce1b0..2e1f6cc 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_control_misc.erl +++ b/deps/rabbit_common/src/rabbit_control_misc.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_control_misc). diff --git a/rabbitmq-server/deps/rabbit/src/term_to_binary_compat.erl b/deps/rabbit_common/src/rabbit_data_coercion.erl similarity index 72% rename from rabbitmq-server/deps/rabbit/src/term_to_binary_compat.erl rename to deps/rabbit_common/src/rabbit_data_coercion.erl index b5e8f72..22b0dbc 100644 --- a/rabbitmq-server/deps/rabbit/src/term_to_binary_compat.erl +++ b/deps/rabbit_common/src/rabbit_data_coercion.erl @@ -11,14 +11,12 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% --module(term_to_binary_compat). +-module(rabbit_data_coercion). --include("rabbit.hrl"). +-export([to_binary/1]). --export([term_to_binary_1/1]). - -term_to_binary_1(Term) -> - term_to_binary(Term, [{minor_version, 1}]). +to_binary(Val) when is_list(Val) -> list_to_binary(Val); +to_binary(Val) -> Val. diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_error_logger_handler.erl b/deps/rabbit_common/src/rabbit_error_logger_handler.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_error_logger_handler.erl rename to deps/rabbit_common/src/rabbit_error_logger_handler.erl index 9376371..314d0e6 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_error_logger_handler.erl +++ b/deps/rabbit_common/src/rabbit_error_logger_handler.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_error_logger_handler). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_event.erl b/deps/rabbit_common/src/rabbit_event.erl similarity index 98% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_event.erl rename to deps/rabbit_common/src/rabbit_event.erl index 2bfdd96..bd869dd 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_event.erl +++ b/deps/rabbit_common/src/rabbit_event.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_event). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_decorator.erl b/deps/rabbit_common/src/rabbit_exchange_decorator.erl similarity index 98% rename from rabbitmq-server/deps/rabbit/src/rabbit_exchange_decorator.erl rename to deps/rabbit_common/src/rabbit_exchange_decorator.erl index 4a545df..a43991b 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_exchange_decorator.erl +++ b/deps/rabbit_common/src/rabbit_exchange_decorator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_decorator). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_exchange_type.erl b/deps/rabbit_common/src/rabbit_exchange_type.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_exchange_type.erl rename to deps/rabbit_common/src/rabbit_exchange_type.erl index 8fd86d8..5f282d1 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_exchange_type.erl +++ b/deps/rabbit_common/src/rabbit_exchange_type.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_health_check.erl b/deps/rabbit_common/src/rabbit_health_check.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_health_check.erl rename to deps/rabbit_common/src/rabbit_health_check.erl index d8d4cc2..f3bc3fa 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_health_check.erl +++ b/deps/rabbit_common/src/rabbit_health_check.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_health_check). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_heartbeat.erl b/deps/rabbit_common/src/rabbit_heartbeat.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_heartbeat.erl rename to deps/rabbit_common/src/rabbit_heartbeat.erl index ac78702..c9b3669 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_heartbeat.erl +++ b/deps/rabbit_common/src/rabbit_heartbeat.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_heartbeat). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_misc.erl b/deps/rabbit_common/src/rabbit_misc.erl similarity index 95% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_misc.erl rename to deps/rabbit_common/src/rabbit_misc.erl index 9e18924..75cee8b 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_misc.erl +++ b/deps/rabbit_common/src/rabbit_misc.erl @@ -11,21 +11,14 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_misc). - --ignore_xref([{maps, get, 2}]). - -include("rabbit.hrl"). -include("rabbit_framing.hrl"). -include("rabbit_misc.hrl"). --ifdef(TEST). --export([decompose_pid/1, compose_pid/4]). --endif. - -export([method_record_type/1, polite_pause/0, polite_pause/1]). -export([die/1, frame_error/2, amqp_error/4, quit/1, protocol_error/3, protocol_error/4, protocol_error/1]). @@ -40,7 +33,7 @@ -export([confirm_to_sender/2]). -export([throw_on_error/2, with_exit_handler/2, is_abnormal_exit/1, filter_exit_map/2]). --export([with_user/2]). +-export([with_user/2, with_user_and_vhost/3]). -export([execute_mnesia_transaction/1]). -export([execute_mnesia_transaction/2]). -export([execute_mnesia_tx_with_tail/1]). @@ -63,13 +56,13 @@ -export([const/1]). -export([ntoa/1, ntoab/1]). -export([is_process_alive/1]). --export([pget/2, pget/3, pupdate/3, pget_or_die/2, pmerge/3, pset/3, plmerge/2]). +-export([pget/2, pget/3, pget_or_die/2, pmerge/3, pset/3, plmerge/2]). -export([format_message_queue/2]). -export([append_rpc_all_nodes/4]). -export([os_cmd/1]). -export([is_os_process_alive/1]). -export([gb_sets_difference/2]). --export([version/0, otp_release/0, platform_and_version/0, which_applications/0]). +-export([version/0, otp_release/0, which_applications/0]). -export([sequence_error/1]). -export([json_encode/1, json_decode/1, json_to_term/1, term_to_json/1]). -export([check_expiry/1]). @@ -79,13 +72,12 @@ -export([get_parent/0]). -export([store_proc_name/1, store_proc_name/2, get_proc_name/0]). -export([moving_average/4]). --export([get_env/3, lists_droplast/1]). +-export([get_env/3]). -export([get_channel_operation_timeout/0]). -export([random/1]). -export([rpc_call/4, rpc_call/5, rpc_call/7]). -export([report_default_thread_pool_size/0]). -export([get_gc_info/1]). --export([group_proplists_by/2]). %% Horrible macro to use in guards -define(IS_BENIGN_EXIT(R), @@ -177,12 +169,14 @@ -spec is_abnormal_exit(any()) -> boolean(). -spec filter_exit_map(fun ((A) -> B), [A]) -> [B]. -spec with_user(rabbit_types:username(), thunk(A)) -> A. +-spec with_user_and_vhost + (rabbit_types:username(), rabbit_types:vhost(), thunk(A)) -> A. -spec execute_mnesia_transaction(thunk(A)) -> A. -spec execute_mnesia_transaction(thunk(A), fun ((A, boolean()) -> B)) -> B. -spec execute_mnesia_tx_with_tail (thunk(fun ((boolean()) -> B))) -> B | (fun ((boolean()) -> B)). -spec ensure_ok(ok_or_error(), atom()) -> 'ok'. --spec tcp_name(atom(), inet:ip_address(), rabbit_net:ip_port()) -> +-spec tcp_name(atom(), inet:ip_address(), rabbit_networking:ip_port()) -> atom(). -spec format_inet_error(atom()) -> string(). -spec upmap(fun ((A) -> B), [A]) -> [B]. @@ -242,7 +236,6 @@ -spec gb_sets_difference(?GB_SET_TYPE(), ?GB_SET_TYPE()) -> ?GB_SET_TYPE(). -spec version() -> string(). -spec otp_release() -> string(). --spec platform_and_version() -> string(). -spec which_applications() -> [{atom(), string(), string()}]. -spec sequence_error([({'error', any()} | any())]) -> {'error', any()} | any(). @@ -275,9 +268,6 @@ (node(), atom(), atom(), [any()], reference(), pid(), number()) -> any(). -spec report_default_thread_pool_size() -> 'ok'. -spec get_gc_info(pid()) -> integer(). --spec group_proplists_by(fun((proplists:proplist()) -> any()), - list(proplists:proplist())) -> list(list(proplists:proplist())). - %%---------------------------------------------------------------------------- @@ -442,7 +432,7 @@ enable_cover(Dirs) -> end, ok, Dirs). start_cover(NodesS) -> - {ok, _} = cover:start([rabbit_nodes_common:make(N) || N <- NodesS]), + {ok, _} = cover:start([rabbit_nodes:make(N) || N <- NodesS]), ok. report_cover() -> report_cover(["."]). @@ -533,6 +523,9 @@ with_user(Username, Thunk) -> end end. +with_user_and_vhost(Username, VHostPath, Thunk) -> + with_user(Username, rabbit_vhost:with(VHostPath, Thunk)). + execute_mnesia_transaction(TxFun) -> %% Making this a sync_transaction allows us to use dirty_read %% elsewhere and get a consistent result even when that read @@ -735,11 +728,9 @@ node_to_fake_pid(Node) -> decompose_pid(Pid) when is_pid(Pid) -> %% see http://erlang.org/doc/apps/erts/erl_ext_dist.html (8.10 and %% 8.7) - Node = node(Pid), - BinPid = term_to_binary(Pid), - ByteSize = byte_size(BinPid), - NodeByteSize = (ByteSize - 11), - <<131, 103, _NodePrefix:NodeByteSize/binary, Id:32, Ser:32, Cre:8>> = BinPid, + <<131,103,100,NodeLen:16,NodeBin:NodeLen/binary,Id:32,Ser:32,Cre:8>> + = term_to_binary(Pid), + Node = binary_to_term(<<131,100,NodeLen:16,NodeBin:NodeLen/binary>>), {Node, Cre, Id, Ser}. compose_pid(Node, Cre, Id, Ser) -> @@ -804,13 +795,15 @@ gb_trees_foreach(Fun, Tree) -> gb_trees_fold(fun (Key, Val, Acc) -> Fun(Key, Val), Acc end, ok, Tree). module_attributes(Module) -> - try - Module:module_info(attributes) - catch - _:undef -> + case catch Module:module_info(attributes) of + {'EXIT', {undef, [{Module, module_info, _} | _]}} -> io:format("WARNING: module ~p not found, so not scanned for boot steps.~n", [Module]), - [] + []; + {'EXIT', Reason} -> + exit(Reason); + V -> + V end. all_module_attributes(Name) -> @@ -871,8 +864,6 @@ ntoab(IP) -> %% See also rabbit_mnesia:is_process_alive/1 which also requires the %% process be in the same running cluster as us (i.e. not partitioned %% or some random node). -is_process_alive(Pid) when node(Pid) =:= node() -> - erlang:is_process_alive(Pid); is_process_alive(Pid) -> Node = node(Pid), lists:member(Node, [node() | nodes()]) andalso @@ -899,15 +890,7 @@ pget_or_die(K, P) -> V -> V end. -pupdate(K, UpdateFun, P) -> - case lists:keyfind(K, 1, P) of - {K, V} -> - pset(K, UpdateFun(V), P); - _ -> - undefined - end. - -%% property merge +%% property merge pmerge(Key, Val, List) -> case proplists:is_defined(Key, List) of true -> List; @@ -917,18 +900,11 @@ pmerge(Key, Val, List) -> %% proplists merge plmerge(P1, P2) -> dict:to_list(dict:merge(fun(_, V, _) -> - V - end, - dict:from_list(P1), + V + end, + dict:from_list(P1), dict:from_list(P2))). -%% groups a list of proplists by a key function -group_proplists_by(KeyFun, ListOfPropLists) -> - Res = lists:foldl(fun(P, Agg) -> - dict:update(KeyFun(P), fun (O) -> [P|O] end, [P], Agg) - end, dict:new(), ListOfPropLists), - [ X || {_, X} <- dict:to_list(Res)]. - pset(Key, Value, List) -> [{Key, Value} | proplists:delete(Key, List)]. format_message_queue(_Opt, MQ) -> @@ -1027,9 +1003,6 @@ otp_release() -> erlang:system_info(otp_release) end. -platform_and_version() -> - string:join(["Erlang/OTP", otp_release()], " "). - %% application:which_applications(infinity) is dangerous, since it can %% cause deadlocks on shutdown. So we have to use a timeout variant, %% but w/o creating spurious timeout errors. The timeout value is twice @@ -1154,10 +1127,6 @@ get_env(Application, Key, Def) -> undefined -> Def end. -%% lists:droplast/1 is only available in Erlang 17.0+. -lists_droplast([_T]) -> []; -lists_droplast([H|T]) -> [H|lists_droplast(T)]. - get_channel_operation_timeout() -> %% Default channel_operation_timeout set to net_ticktime + 10s to %% give allowance for any down messages to be received first, diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_msg_store_index.erl b/deps/rabbit_common/src/rabbit_msg_store_index.erl similarity index 96% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_msg_store_index.erl rename to deps/rabbit_common/src/rabbit_msg_store_index.erl index 64672f1..b33cd4f 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_msg_store_index.erl +++ b/deps/rabbit_common/src/rabbit_msg_store_index.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_msg_store_index). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_net.erl b/deps/rabbit_common/src/rabbit_net.erl similarity index 90% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_net.erl rename to deps/rabbit_common/src/rabbit_net.erl index 33ea360..792eb55 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_net.erl +++ b/deps/rabbit_common/src/rabbit_net.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_net). @@ -24,18 +24,17 @@ -type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'. -endif. --include_lib("kernel/include/inet.hrl"). -include_lib("ssl/src/ssl_api.hrl"). -export([is_ssl/1, ssl_info/1, controlling_process/2, getstat/2, recv/1, sync_recv/2, async_recv/3, port_command/2, getopts/2, setopts/2, send/2, close/1, fast_close/1, sockname/1, peername/1, peercert/1, connection_string/2, socket_ends/2, is_loopback/1, - tcp_host/1]). + accept_ack/2]). %%--------------------------------------------------------------------------- --export_type([socket/0, ip_port/0, hostname/0]). +-export_type([socket/0]). -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | @@ -45,8 +44,6 @@ -type socket() :: port() | ssl:sslsocket(). -type opts() :: [{atom(), any()} | {raw, non_neg_integer(), non_neg_integer(), binary()}]. --type hostname() :: inet:hostname(). --type ip_port() :: inet:port_number(). -type host_or_ip() :: binary() | inet:ip_address(). -spec is_ssl(socket()) -> boolean(). -spec ssl_info(socket()) -> 'nossl' | ok_val_or_error([{atom(), any()}]). @@ -75,17 +72,18 @@ -spec close(socket()) -> ok_or_any_error(). -spec fast_close(socket()) -> ok_or_any_error(). -spec sockname(socket()) -> - ok_val_or_error({inet:ip_address(), ip_port()}). + ok_val_or_error({inet:ip_address(), rabbit_networking:ip_port()}). -spec peername(socket()) -> - ok_val_or_error({inet:ip_address(), ip_port()}). + ok_val_or_error({inet:ip_address(), rabbit_networking:ip_port()}). -spec peercert(socket()) -> 'nossl' | ok_val_or_error(rabbit_ssl:certificate()). -spec connection_string(socket(), 'inbound' | 'outbound') -> ok_val_or_error(string()). -spec socket_ends(socket(), 'inbound' | 'outbound') -> - ok_val_or_error({host_or_ip(), ip_port(), - host_or_ip(), ip_port()}). + ok_val_or_error({host_or_ip(), rabbit_networking:ip_port(), + host_or_ip(), rabbit_networking:ip_port()}). -spec is_loopback(socket() | inet:ip_address()) -> boolean(). +-spec accept_ack(any(), socket()) -> ok. %%--------------------------------------------------------------------------- @@ -236,28 +234,9 @@ socket_ends(Sock, Direction) -> maybe_ntoab(Addr) when is_tuple(Addr) -> rabbit_misc:ntoab(Addr); maybe_ntoab(Host) -> Host. -tcp_host({0,0,0,0}) -> - hostname(); - -tcp_host({0,0,0,0,0,0,0,0}) -> - hostname(); - -tcp_host(IPAddress) -> - case inet:gethostbyaddr(IPAddress) of - {ok, #hostent{h_name = Name}} -> Name; - {error, _Reason} -> rabbit_misc:ntoa(IPAddress) - end. - -hostname() -> - {ok, Hostname} = inet:gethostname(), - case inet:gethostbyname(Hostname) of - {ok, #hostent{h_name = Name}} -> Name; - {error, _Reason} -> Hostname - end. - rdns(Addr) -> case application:get_env(rabbit, reverse_dns_lookups) of - {ok, true} -> list_to_binary(tcp_host(Addr)); + {ok, true} -> list_to_binary(rabbit_networking:tcp_host(Addr)); _ -> Addr end. @@ -277,3 +256,19 @@ is_loopback({0,0,0,0,0,65535,AB,CD}) -> is_loopback(ipv4(AB, CD)); is_loopback(_) -> false. ipv4(AB, CD) -> {AB bsr 8, AB band 255, CD bsr 8, CD band 255}. + +accept_ack(Ref, Sock) -> + ok = ranch:accept_ack(Ref), + case tune_buffer_size(Sock) of + ok -> ok; + {error, _} -> rabbit_net:fast_close(Sock), + exit(normal) + end, + ok = file_handle_cache:obtain(). + +tune_buffer_size(Sock) -> + case getopts(Sock, [sndbuf, recbuf, buffer]) of + {ok, BufSizes} -> BufSz = lists:max([Sz || {_Opt, Sz} <- BufSizes]), + setopts(Sock, [{buffer, BufSz}]); + Error -> Error + end. diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_networking.erl b/deps/rabbit_common/src/rabbit_networking.erl similarity index 81% rename from rabbitmq-server/deps/rabbit/src/rabbit_networking.erl rename to deps/rabbit_common/src/rabbit_networking.erl index 8b201fd..5bf30ff 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_networking.erl +++ b/deps/rabbit_common/src/rabbit_networking.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_networking). @@ -34,29 +34,34 @@ connections/0, connection_info_keys/0, connection_info/1, connection_info/2, connection_info_all/0, connection_info_all/1, connection_info_all/3, - close_connection/2, force_connection_event_refresh/1, accept_ack/2, - tcp_host/1]). + close_connection/2, force_connection_event_refresh/1, tcp_host/1]). %% Used by TCP-based transports, e.g. STOMP adapter -export([tcp_listener_addresses/1, tcp_listener_spec/9, ensure_ssl/0, fix_ssl_options/1, poodle_check/1]). --export([tcp_listener_started/4, tcp_listener_stopped/4]). +-export([tcp_listener_started/3, tcp_listener_stopped/3]). %% Internal -export([connections_local/0]). +-import(rabbit_misc, [pget/2, pget/3, pset/3]). + -include("rabbit.hrl"). +-include_lib("kernel/include/inet.hrl"). %% IANA-suggested ephemeral port range is 49152 to 65535 -define(FIRST_TEST_BIND_PORT, 49152). +%% POODLE +-define(BAD_SSL_PROTOCOL_VERSIONS, [sslv3]). + %%---------------------------------------------------------------------------- -export_type([ip_port/0, hostname/0]). --type hostname() :: rabbit_net:hostname(). --type ip_port() :: rabbit_net:ip_port(). +-type hostname() :: inet:hostname(). +-type ip_port() :: inet:port_number(). -type family() :: atom(). -type listener_config() :: ip_port() | @@ -88,7 +93,6 @@ 'ok'. -spec close_connection(pid(), string()) -> 'ok'. -spec force_connection_event_refresh(reference()) -> 'ok'. --spec accept_ack(any(), rabbit_net:socket()) -> ok. -spec on_node_down(node()) -> 'ok'. -spec tcp_listener_addresses(listener_config()) -> [address()]. @@ -97,17 +101,18 @@ protocol(), any(), non_neg_integer(), label()) -> supervisor:child_spec(). -spec ensure_ssl() -> rabbit_types:infos(). +-spec fix_ssl_options(rabbit_types:infos()) -> rabbit_types:infos(). -spec poodle_check(atom()) -> 'ok' | 'danger'. -spec boot() -> 'ok'. -spec tcp_listener_started - (_, _, + (_, string() | {byte(),byte(),byte(),byte()} | {char(),char(),char(),char(),char(),char(),char(),char()}, _) -> 'ok'. -spec tcp_listener_stopped - (_, _, + (_, string() | {byte(),byte(),byte(),byte()} | {char(),char(),char(),char(),char(),char(),char(),char()}, @@ -144,7 +149,7 @@ ensure_ssl() -> {ok, SslAppsConfig} = application:get_env(rabbit, ssl_apps), ok = app_utils:start_applications(SslAppsConfig), {ok, SslOptsConfig} = application:get_env(rabbit, ssl_options), - rabbit_ssl_options:fix(SslOptsConfig). + fix_ssl_options(SslOptsConfig). poodle_check(Context) -> {ok, Vsn} = application:get_key(ssl, vsn), @@ -172,7 +177,70 @@ log_poodle_fail(Context) -> [rabbit_misc:otp_release(), Context]). fix_ssl_options(Config) -> - rabbit_ssl_options:fix(Config). + fix_verify_fun(fix_ssl_protocol_versions(Config)). + +fix_verify_fun(SslOptsConfig) -> + %% Starting with ssl 4.0.1 in Erlang R14B, the verify_fun function + %% takes 3 arguments and returns a tuple. + case rabbit_misc:pget(verify_fun, SslOptsConfig) of + {Module, Function, InitialUserState} -> + Fun = make_verify_fun(Module, Function, InitialUserState), + rabbit_misc:pset(verify_fun, Fun, SslOptsConfig); + {Module, Function} when is_atom(Module) -> + Fun = make_verify_fun(Module, Function, none), + rabbit_misc:pset(verify_fun, Fun, SslOptsConfig); + {Verifyfun, _InitialUserState} when is_function(Verifyfun, 3) -> + SslOptsConfig; + undefined -> + SslOptsConfig + end. + +make_verify_fun(Module, Function, InitialUserState) -> + try + %% Preload the module: it is required to use + %% erlang:function_exported/3. + Module:module_info() + catch + _:Exception -> + rabbit_log:error("SSL verify_fun: module ~s missing: ~p~n", + [Module, Exception]), + throw({error, {invalid_verify_fun, missing_module}}) + end, + NewForm = erlang:function_exported(Module, Function, 3), + OldForm = erlang:function_exported(Module, Function, 1), + case {NewForm, OldForm} of + {true, _} -> + %% This verify_fun is supported by Erlang R14B+ (ssl + %% 4.0.1 and later). + Fun = fun(OtpCert, Event, UserState) -> + Module:Function(OtpCert, Event, UserState) + end, + {Fun, InitialUserState}; + {_, true} -> + %% This verify_fun is supported by Erlang R14B+ for + %% undocumented backward compatibility. + %% + %% InitialUserState is ignored in this case. + fun(Args) -> + Module:Function(Args) + end; + _ -> + rabbit_log:error("SSL verify_fun: no ~s:~s/3 exported~n", + [Module, Function]), + throw({error, {invalid_verify_fun, function_not_exported}}) + end. + +fix_ssl_protocol_versions(Config) -> + case application:get_env(rabbit, ssl_allow_poodle_attack) of + {ok, true} -> + Config; + _ -> + Configured = case pget(versions, Config) of + undefined -> pget(available, ssl:versions(), []); + Vs -> Vs + end, + pset(versions, Configured -- ?BAD_SSL_PROTOCOL_VERSIONS, Config) + end. tcp_listener_addresses(Port) when is_integer(Port) -> tcp_listener_addresses_auto(Port); @@ -199,8 +267,8 @@ tcp_listener_spec(NamePrefix, {IPAddress, Port, Family}, SocketOpts, {rabbit_misc:tcp_name(NamePrefix, IPAddress, Port), {tcp_listener_sup, start_link, [IPAddress, Port, Transport, [Family | SocketOpts], ProtoSup, ProtoOpts, - {?MODULE, tcp_listener_started, [Protocol, SocketOpts]}, - {?MODULE, tcp_listener_stopped, [Protocol, SocketOpts]}, + {?MODULE, tcp_listener_started, [Protocol]}, + {?MODULE, tcp_listener_stopped, [Protocol]}, NumAcceptors, Label]}, transient, infinity, supervisor, [tcp_listener_sup]}. @@ -240,7 +308,7 @@ stop_tcp_listener0({IPAddress, Port, _Family}) -> ok = supervisor:terminate_child(rabbit_sup, Name), ok = supervisor:delete_child(rabbit_sup, Name). -tcp_listener_started(Protocol, Opts, IPAddress, Port) -> +tcp_listener_started(Protocol, IPAddress, Port) -> %% We need the ip to distinguish e.g. 0.0.0.0 and 127.0.0.1 %% We need the host so we can distinguish multiple instances of the above %% in a cluster. @@ -250,23 +318,21 @@ tcp_listener_started(Protocol, Opts, IPAddress, Port) -> protocol = Protocol, host = tcp_host(IPAddress), ip_address = IPAddress, - port = Port, - opts = Opts}). + port = Port}). -tcp_listener_stopped(Protocol, Opts, IPAddress, Port) -> +tcp_listener_stopped(Protocol, IPAddress, Port) -> ok = mnesia:dirty_delete_object( rabbit_listener, #listener{node = node(), protocol = Protocol, host = tcp_host(IPAddress), ip_address = IPAddress, - port = Port, - opts = Opts}). + port = Port}). record_distribution_listener() -> {Name, Host} = rabbit_nodes:parts(node()), {port, Port, _Version} = erl_epmd:port_please(Name, Host), - tcp_listener_started(clustering, [], {0,0,0,0,0,0,0,0}, Port). + tcp_listener_started(clustering, {0,0,0,0,0,0,0,0}, Port). active_listeners() -> rabbit_misc:dirty_read_all(rabbit_listener). @@ -315,26 +381,26 @@ force_connection_event_refresh(Ref) -> [rabbit_reader:force_event_refresh(C, Ref) || C <- connections()], ok. -accept_ack(Ref, Sock) -> - ok = ranch:accept_ack(Ref), - case tune_buffer_size(Sock) of - ok -> ok; - {error, _} -> rabbit_net:fast_close(Sock), - exit(normal) - end, - ok = file_handle_cache:obtain(). +%%-------------------------------------------------------------------- -tune_buffer_size(Sock) -> - case rabbit_net:getopts(Sock, [sndbuf, recbuf, buffer]) of - {ok, BufSizes} -> BufSz = lists:max([Sz || {_Opt, Sz} <- BufSizes]), - rabbit_net:setopts(Sock, [{buffer, BufSz}]); - Error -> Error - end. +tcp_host({0,0,0,0}) -> + hostname(); -%%-------------------------------------------------------------------- +tcp_host({0,0,0,0,0,0,0,0}) -> + hostname(); tcp_host(IPAddress) -> - rabbit_net:tcp_host(IPAddress). + case inet:gethostbyaddr(IPAddress) of + {ok, #hostent{h_name = Name}} -> Name; + {error, _Reason} -> rabbit_misc:ntoa(IPAddress) + end. + +hostname() -> + {ok, Hostname} = inet:gethostname(), + case inet:gethostbyname(Hostname) of + {ok, #hostent{h_name = Name}} -> Name; + {error, _Reason} -> Hostname + end. cmap(F) -> rabbit_misc:filter_exit_map(F, connections()). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_nodes.erl b/deps/rabbit_common/src/rabbit_nodes.erl similarity index 87% rename from rabbitmq-server/deps/rabbit/src/rabbit_nodes.erl rename to deps/rabbit_common/src/rabbit_nodes.erl index 6bb6d34..70a5355 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_nodes.erl +++ b/deps/rabbit_common/src/rabbit_nodes.erl @@ -1,5 +1,4 @@ %% The contents of this file are subject to the Mozilla Public License - %% Version 1.1 (the "License"); you may not use this file except in %% compliance with the License. You may obtain a copy of the License %% at http://www.mozilla.org/MPL/ @@ -12,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_nodes). @@ -35,11 +34,14 @@ -spec names(string()) -> rabbit_types:ok_or_error2([{string(), integer()}], term()). -spec diagnostics([node()]) -> string(). +-spec make({string(), string()} | string()) -> node(). +-spec parts(node() | string()) -> {string(), string()}. -spec cookie_hash() -> string(). -spec is_running(node(), atom()) -> boolean(). -spec is_process_running(node(), atom()) -> boolean(). -spec cluster_name() -> binary(). -spec set_cluster_name(binary()) -> 'ok'. +-spec ensure_epmd() -> 'ok'. -spec all_running() -> [node()]. %%---------------------------------------------------------------------------- @@ -175,11 +177,17 @@ diagnose_connect(Host, Port) -> E end. -make(NodeStr) -> - rabbit_nodes_common:make(NodeStr). +make({Prefix, Suffix}) -> list_to_atom(lists:append([Prefix, "@", Suffix])); +make(NodeStr) -> make(parts(NodeStr)). +parts(Node) when is_atom(Node) -> + parts(atom_to_list(Node)); parts(NodeStr) -> - rabbit_nodes_common:parts(NodeStr). + case lists:splitwith(fun (E) -> E =/= $@ end, NodeStr) of + {Prefix, []} -> {_, Suffix} = parts(node()), + {Prefix, Suffix}; + {Prefix, Suffix} -> {Prefix, tl(Suffix)} + end. cookie_hash() -> base64:encode_to_string(erlang:md5(atom_to_list(erlang:get_cookie()))). @@ -211,6 +219,19 @@ set_cluster_name(Name) -> rabbit_runtime_parameters:set_global(cluster_name, Name). ensure_epmd() -> - rabbit_nodes_common:ensure_epmd(). + {ok, Prog} = init:get_argument(progname), + ID = rabbit_misc:random(1000000000), + Port = open_port( + {spawn_executable, os:find_executable(Prog)}, + [{args, ["-sname", rabbit_misc:format("epmd-starter-~b", [ID]), + "-noshell", "-eval", "halt()."]}, + exit_status, stderr_to_stdout, use_stdio]), + port_shutdown_loop(Port). + +port_shutdown_loop(Port) -> + receive + {Port, {exit_status, _Rc}} -> ok; + {Port, _} -> port_shutdown_loop(Port) + end. all_running() -> rabbit_mnesia:cluster_nodes(running). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_password_hashing.erl b/deps/rabbit_common/src/rabbit_password_hashing.erl similarity index 91% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_password_hashing.erl rename to deps/rabbit_common/src/rabbit_password_hashing.erl index f80258a..fd2ba70 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_password_hashing.erl +++ b/deps/rabbit_common/src/rabbit_password_hashing.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_password_hashing). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_policy_validator.erl b/deps/rabbit_common/src/rabbit_policy_validator.erl similarity index 92% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_policy_validator.erl rename to deps/rabbit_common/src/rabbit_policy_validator.erl index 9a309c8..110a26c 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_policy_validator.erl +++ b/deps/rabbit_common/src/rabbit_policy_validator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_policy_validator). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_collector.erl b/deps/rabbit_common/src/rabbit_queue_collector.erl similarity index 95% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_collector.erl rename to deps/rabbit_common/src/rabbit_queue_collector.erl index 6329b0b..82a891a 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_collector.erl +++ b/deps/rabbit_common/src/rabbit_queue_collector.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_collector). @@ -34,6 +34,7 @@ -spec start_link(rabbit_types:proc_name()) -> rabbit_types:ok_pid_or_error(). -spec register(pid(), pid()) -> 'ok'. +-spec delete_all(pid()) -> 'ok'. %%---------------------------------------------------------------------------- @@ -44,7 +45,7 @@ register(CollectorPid, Q) -> gen_server:call(CollectorPid, {register, Q}, infinity). delete_all(CollectorPid) -> - rabbit_queue_collector_common:delete_all(CollectorPid). + gen_server:call(CollectorPid, delete_all, infinity). %%---------------------------------------------------------------------------- diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_queue_decorator.erl b/deps/rabbit_common/src/rabbit_queue_decorator.erl similarity index 97% rename from rabbitmq-server/deps/rabbit/src/rabbit_queue_decorator.erl rename to deps/rabbit_common/src/rabbit_queue_decorator.erl index fa0bafa..ee24802 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_queue_decorator.erl +++ b/deps/rabbit_common/src/rabbit_queue_decorator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_decorator). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_queue_master_locator.erl b/deps/rabbit_common/src/rabbit_queue_master_locator.erl similarity index 92% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_queue_master_locator.erl rename to deps/rabbit_common/src/rabbit_queue_master_locator.erl index 34f4fe4..21596ff 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_queue_master_locator.erl +++ b/deps/rabbit_common/src/rabbit_queue_master_locator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_queue_master_locator). diff --git a/rabbitmq-server/deps/rabbit/src/rabbit_reader.erl b/deps/rabbit_common/src/rabbit_reader.erl similarity index 94% rename from rabbitmq-server/deps/rabbit/src/rabbit_reader.erl rename to deps/rabbit_common/src/rabbit_reader.erl index 24de35e..e5aeadc 100644 --- a/rabbitmq-server/deps/rabbit/src/rabbit_reader.erl +++ b/deps/rabbit_common/src/rabbit_reader.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_reader). @@ -159,10 +159,6 @@ send_pend, state, channels, reductions, garbage_collection]). --define(SIMPLE_METRICS, [pid, recv_oct, send_oct, reductions]). --define(OTHER_METRICS, [recv_cnt, send_cnt, send_pend, state, channels, - garbage_collection]). - -define(CREATION_EVENT_KEYS, [pid, name, port, peer_port, host, peer_host, ssl, peer_cert_subject, peer_cert_issuer, @@ -231,7 +227,7 @@ shutdown(Pid, Explanation) -> gen_server:call(Pid, {shutdown, Explanation}, infinity). init(Parent, HelperSup, Ref, Sock) -> - rabbit_networking:accept_ack(Ref, Sock), + rabbit_net:accept_ack(Ref, Sock), Deb = sys:debug_options([]), start_connection(Parent, HelperSup, Deb, Sock). @@ -263,7 +259,7 @@ conserve_resources(Pid, Source, {_, Conserve, _}) -> ok. server_properties(Protocol) -> - {ok, Product} = application:get_key(rabbit, description), + {ok, Product} = application:get_key(rabbit, id), {ok, Version} = application:get_key(rabbit, vsn), %% Get any configuration-specified server properties @@ -283,7 +279,7 @@ server_properties(Protocol) -> [{product, Product}, {version, Version}, {cluster_name, rabbit_nodes:cluster_name()}, - {platform, rabbit_misc:platform_and_version()}, + {platform, "Erlang/OTP"}, {copyright, ?COPYRIGHT_MESSAGE}, {information, ?INFORMATION_MESSAGE}]]], @@ -387,20 +383,11 @@ start_connection(Parent, HelperSup, Deb, Sock) -> last_blocked_by = none, last_blocked_at = never}}, try - case run({?MODULE, recvloop, - [Deb, [], 0, switch_callback(rabbit_event:init_stats_timer( - State, #v1.stats_timer), - handshake, 8)]}) of - %% connection was closed cleanly by the client - #v1{connection = #connection{user = #user{username = Username}, - vhost = VHost}} -> - log(info, "closing AMQP connection ~p (~s, vhost: '~s', user: '~s')~n", - [self(), dynamic_connection_name(Name), VHost, Username]); - %% just to be more defensive - _ -> - log(info, "closing AMQP connection ~p (~s)~n", - [self(), dynamic_connection_name(Name)]) - end + run({?MODULE, recvloop, + [Deb, [], 0, switch_callback(rabbit_event:init_stats_timer( + State, #v1.stats_timer), + handshake, 8)]}), + log(info, "closing AMQP connection ~p (~s)~n", [self(), dynamic_connection_name(Name)]) catch Ex -> log_connection_exception(dynamic_connection_name(Name), Ex) @@ -414,7 +401,6 @@ start_connection(Parent, HelperSup, Deb, Sock) -> %% socket w/o delay before termination. rabbit_net:fast_close(Sock), rabbit_networking:unregister_connection(self()), - rabbit_core_metrics:connection_closed(self()), rabbit_event:notify(connection_closed, [{pid, self()}]) end, done. @@ -422,7 +408,6 @@ start_connection(Parent, HelperSup, Deb, Sock) -> log_connection_exception(Name, Ex) -> Severity = case Ex of connection_closed_with_no_data_received -> debug; - {connection_closed_abruptly, _} -> warning; connection_closed_abruptly -> warning; _ -> error end, @@ -432,17 +417,6 @@ log_connection_exception(Severity, Name, {heartbeat_timeout, TimeoutSec}) -> %% Long line to avoid extra spaces and line breaks in log log(Severity, "closing AMQP connection ~p (~s):~nmissed heartbeats from client, timeout: ~ps~n", [self(), Name, TimeoutSec]); -log_connection_exception(Severity, Name, {connection_closed_abruptly, - #v1{connection = #connection{user = #user{username = Username}, - vhost = VHost}}}) -> - log(Severity, "closing AMQP connection ~p (~s, vhost: '~s', user: '~s'):~nclient unexpectedly closed TCP connection~n", - [self(), Name, VHost, Username]); -%% when client abruptly closes connection before connection.open/authentication/authorization -%% succeeded, don't log username and vhost as 'none' -log_connection_exception(Severity, Name, {connection_closed_abruptly, _}) -> - log(Severity, "closing AMQP connection ~p (~s):~nclient unexpectedly closed TCP connection~n", - [self(), Name]); -%% old exception structure log_connection_exception(Severity, Name, connection_closed_abruptly) -> log(Severity, "closing AMQP connection ~p (~s):~nclient unexpectedly closed TCP connection~n", [self(), Name]); @@ -511,7 +485,7 @@ mainloop(Deb, Buf, BufLen, State = #v1{sock = Sock, recvloop(Deb, [Data | Buf], BufLen + size(Data), State#v1{pending_recv = false}); closed when State#v1.connection_state =:= closed -> - State; + ok; closed when CS =:= pre_init andalso Buf =:= [] -> stop(tcp_healthcheck, State); closed -> @@ -527,7 +501,7 @@ mainloop(Deb, Buf, BufLen, State = #v1{sock = Sock, ?MODULE, Deb, {Buf, BufLen, State}); {other, Other} -> case handle_other(Other, State) of - stop -> State; + stop -> ok; NewState -> recvloop(Deb, Buf, BufLen, NewState) end end. @@ -540,7 +514,7 @@ stop(tcp_healthcheck, State) -> throw(connection_closed_with_no_data_received); stop(closed, State) -> maybe_emit_stats(State), - throw({connection_closed_abruptly, State}); + throw(connection_closed_abruptly); stop(Reason, State) -> maybe_emit_stats(State), throw({inet_error, Reason}). @@ -744,12 +718,10 @@ handle_dependent_exit(ChPid, Reason, State) -> {Channel, State1} = channel_cleanup(ChPid, State), case {Channel, termination_kind(Reason)} of {undefined, controlled} -> State1; - {undefined, uncontrolled} -> handle_uncontrolled_channel_close(ChPid), - exit({abnormal_dependent_exit, + {undefined, uncontrolled} -> exit({abnormal_dependent_exit, ChPid, Reason}); {_, controlled} -> maybe_close(control_throttle(State1)); - {_, uncontrolled} -> handle_uncontrolled_channel_close(ChPid), - State2 = handle_exception( + {_, uncontrolled} -> State2 = handle_exception( State1, Channel, Reason), maybe_close(control_throttle(State2)) end. @@ -790,7 +762,6 @@ wait_for_channel_termination(N, TimerRef, "error while terminating:~n~p~n", [self(), ConnName, VHost, User#user.username, CS, Channel, Reason]), - handle_uncontrolled_channel_close(ChPid), wait_for_channel_termination(N-1, TimerRef, State1) end; {'EXIT', Sock, _Reason} -> @@ -1150,7 +1121,7 @@ handle_method0(MethodName, FieldsBin, State) catch throw:{inet_error, E} when E =:= closed; E =:= enotconn -> maybe_emit_stats(State), - throw({connection_closed_abruptly, State}); + throw(connection_closed_abruptly); exit:#amqp_error{method = none} = Reason -> handle_exception(State, 0, Reason#amqp_error{method = MethodName}); Type:Reason -> @@ -1223,17 +1194,16 @@ handle_method0(#'connection.tune_ok'{frame_max = FrameMax, queue_collector = Collector, heartbeater = Heartbeater}; -handle_method0(#'connection.open'{virtual_host = VHost}, +handle_method0(#'connection.open'{virtual_host = VHostPath}, State = #v1{connection_state = opening, connection = Connection = #connection{ - log_name = ConnName, - user = User = #user{username = Username}, + user = User, protocol = Protocol}, helper_sup = SupPid, sock = Sock, throttle = Throttle}) -> - ok = rabbit_access_control:check_vhost_access(User, VHost, Sock), - NewConnection = Connection#connection{vhost = VHost}, + ok = rabbit_access_control:check_vhost_access(User, VHostPath, Sock), + NewConnection = Connection#connection{vhost = VHostPath}, ok = send_on_channel0(Sock, #'connection.open_ok'{}, Protocol), Conserve = rabbit_alarm:register(self(), {?MODULE, conserve_resources, []}), Throttle1 = Throttle#throttle{alarmed_by = Conserve}, @@ -1244,13 +1214,10 @@ handle_method0(#'connection.open'{virtual_host = VHost}, connection = NewConnection, channel_sup_sup_pid = ChannelSupSupPid, throttle = Throttle1}), - Infos = [{type, network} | infos(?CREATION_EVENT_KEYS, State1)], - rabbit_core_metrics:connection_created(proplists:get_value(pid, Infos), - Infos), - rabbit_event:notify(connection_created, Infos), + rabbit_event:notify(connection_created, + [{type, network} | + infos(?CREATION_EVENT_KEYS, State1)]), maybe_emit_stats(State1), - log(info, "connection ~p (~s): user '~s' authenticated and granted access to vhost '~s'~n", - [self(), ConnName, Username, VHost]), State1; handle_method0(#'connection.close'{}, State) when ?IS_RUNNING(State) -> lists:foreach(fun rabbit_channel:shutdown/1, all_channels()), @@ -1467,11 +1434,8 @@ ic(Item, #connection{}) -> throw({bad_argument, Item}). socket_info(Get, Select, #v1{sock = Sock}) -> case Get(Sock) of - {ok, T} -> case Select(T) of - N when is_number(N) -> N; - _ -> 0 - end; - {error, _} -> 0 + {ok, T} -> Select(T); + {error, _} -> '' end. ssl_info(F, #v1{sock = Sock}) -> @@ -1502,12 +1466,8 @@ maybe_emit_stats(State) -> fun() -> emit_stats(State) end). emit_stats(State) -> - [{_, Pid}, {_, Recv_oct}, {_, Send_oct}, {_, Reductions}] = I - = infos(?SIMPLE_METRICS, State), - Infos = infos(?OTHER_METRICS, State), - rabbit_core_metrics:connection_stats(Pid, Infos), - rabbit_core_metrics:connection_stats(Pid, Recv_oct, Send_oct, Reductions), - rabbit_event:notify(connection_stats, Infos ++ I), + Infos = infos(?STATISTICS_KEYS, State), + rabbit_event:notify(connection_stats, Infos), State1 = rabbit_event:reset_stats_timer(State, #v1.stats_timer), ensure_stats_timer(State1). @@ -1568,7 +1528,3 @@ dynamic_connection_name(Default) -> _ -> Default end. - -handle_uncontrolled_channel_close(ChPid) -> - rabbit_core_metrics:channel_closed(ChPid), - rabbit_event:notify(channel_closed, [{pid, ChPid}]). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_runtime_parameter.erl b/deps/rabbit_common/src/rabbit_runtime_parameter.erl similarity index 94% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_runtime_parameter.erl rename to deps/rabbit_common/src/rabbit_runtime_parameter.erl index 1f55b2e..e287d2f 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_runtime_parameter.erl +++ b/deps/rabbit_common/src/rabbit_runtime_parameter.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_runtime_parameter). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_types.erl b/deps/rabbit_common/src/rabbit_types.erl similarity index 97% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_types.erl rename to deps/rabbit_common/src/rabbit_types.erl index 3daaf81..29a3ef9 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_types.erl +++ b/deps/rabbit_common/src/rabbit_types.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_types). @@ -98,8 +98,8 @@ -type(listener() :: #listener{node :: node(), protocol :: atom(), - host :: rabbit_net:hostname(), - port :: rabbit_net:ip_port()}). + host :: rabbit_networking:hostname(), + port :: rabbit_networking:ip_port()}). -type(binding_source() :: rabbit_exchange:name()). -type(binding_destination() :: rabbit_amqqueue:name() | rabbit_exchange:name()). diff --git a/rabbitmq-server/deps/rabbit_common/src/rabbit_writer.erl b/deps/rabbit_common/src/rabbit_writer.erl similarity index 91% rename from rabbitmq-server/deps/rabbit_common/src/rabbit_writer.erl rename to deps/rabbit_common/src/rabbit_writer.erl index 66f87c3..3884f1a 100644 --- a/rabbitmq-server/deps/rabbit_common/src/rabbit_writer.erl +++ b/deps/rabbit_common/src/rabbit_writer.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_writer). @@ -46,7 +46,6 @@ send_command_flow/2, send_command_flow/3, flush/1]). -export([internal_send_command/4, internal_send_command/6]). --export([msg_size/1, maybe_gc_large_msg/1]). %% internal -export([enter_mainloop/2, mainloop/2, mainloop1/2]). @@ -127,12 +126,6 @@ non_neg_integer(), rabbit_types:protocol()) -> 'ok'. --spec msg_size - (rabbit_types:content() | rabbit_types:message()) -> non_neg_integer(). - --spec maybe_gc_large_msg - (rabbit_types:content() | rabbit_types:message()) -> non_neg_integer(). - %%--------------------------------------------------------------------------- start(Sock, Channel, FrameMax, Protocol, ReaderPid, Identity) -> @@ -235,15 +228,15 @@ handle_message({'$gen_call', From, flush}, State) -> State1; handle_message({send_command_and_notify, QPid, ChPid, MethodRecord}, State) -> State1 = internal_send_command_async(MethodRecord, State), - rabbit_amqqueue_common:notify_sent(QPid, ChPid), + rabbit_amqqueue:notify_sent(QPid, ChPid), State1; handle_message({send_command_and_notify, QPid, ChPid, MethodRecord, Content}, State) -> State1 = internal_send_command_async(MethodRecord, Content, State), - rabbit_amqqueue_common:notify_sent(QPid, ChPid), + rabbit_amqqueue:notify_sent(QPid, ChPid), State1; handle_message({'DOWN', _MRef, process, QPid, _Reason}, State) -> - rabbit_amqqueue_common:notify_sent_queue_down(QPid), + rabbit_amqqueue:notify_sent_queue_down(QPid), State; handle_message({inet_reply, _, ok}, State) -> rabbit_event:ensure_stats_timer(State, #wstate.stats_timer, emit_stats); @@ -340,7 +333,7 @@ internal_send_command_async(MethodRecord, Content, pending = Pending}) -> Frames = assemble_frames(Channel, MethodRecord, Content, FrameMax, Protocol), - maybe_gc_large_msg(Content), + rabbit_basic:maybe_gc_large_msg(Content), maybe_flush(State#wstate{pending = [Frames | Pending]}). %% When the amount of protocol method data buffered exceeds @@ -387,25 +380,3 @@ port_cmd(Sock, Data) -> catch error:Error -> exit({writer, send_failed, Error}) end, ok. - -%% Some processes (channel, writer) can get huge amounts of binary -%% garbage when processing huge messages at high speed (since we only -%% do enough reductions to GC every few hundred messages, and if each -%% message is 1MB then that's ugly). So count how many bytes of -%% message we have processed, and force a GC every so often. -maybe_gc_large_msg(Content) -> - Size = msg_size(Content), - Current = case get(msg_size_for_gc) of - undefined -> 0; - C -> C - end, - New = Current + Size, - put(msg_size_for_gc, case New > 1000000 of - true -> erlang:garbage_collect(), - 0; - false -> New - end), - Size. - -msg_size(#content{payload_fragments_rev = PFR}) -> iolist_size(PFR); -msg_size(#basic_message{content = Content}) -> msg_size(Content). diff --git a/rabbitmq-server/deps/rabbit_common/src/rand_compat.erl b/deps/rabbit_common/src/rand_compat.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/rand_compat.erl rename to deps/rabbit_common/src/rand_compat.erl diff --git a/rabbitmq-server/deps/rabbit_common/src/ssl_compat.erl b/deps/rabbit_common/src/ssl_compat.erl similarity index 95% rename from rabbitmq-server/deps/rabbit_common/src/ssl_compat.erl rename to deps/rabbit_common/src/ssl_compat.erl index 23b8fa1..e007667 100644 --- a/rabbitmq-server/deps/rabbit_common/src/ssl_compat.erl +++ b/deps/rabbit_common/src/ssl_compat.erl @@ -11,13 +11,13 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(ssl_compat). -%% We don't want warnings about the use of ssl:connection_info/1 in this -%% module. +%% We don't want warnings about the use of erlang:now/0 in +%% this module. -compile(nowarn_deprecated_function). %% Declare versioned functions to allow dynamic code loading, diff --git a/rabbitmq-server/deps/rabbit_common/src/supervisor2.erl b/deps/rabbit_common/src/supervisor2.erl similarity index 99% rename from rabbitmq-server/deps/rabbit_common/src/supervisor2.erl rename to deps/rabbit_common/src/supervisor2.erl index 6af2693..22b7868 100644 --- a/rabbitmq-server/deps/rabbit_common/src/supervisor2.erl +++ b/deps/rabbit_common/src/supervisor2.erl @@ -880,8 +880,7 @@ do_restart_delay({RestartType, Delay}, Reason, Child, State) -> _TRef = erlang:send_after(trunc(Delay*1000), self(), {delayed_restart, {{RestartType, Delay}, Reason, Child}}), - OldPid = Child#child.pid, - {ok, replace_child(Child#child{pid=restarting(OldPid)}, State)} + {ok, state_del_child(Child, State)} end. restart(Child, State) -> diff --git a/rabbitmq-server/deps/rabbit_common/src/time_compat.erl b/deps/rabbit_common/src/time_compat.erl similarity index 100% rename from rabbitmq-server/deps/rabbit_common/src/time_compat.erl rename to deps/rabbit_common/src/time_compat.erl diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/CODE_OF_CONDUCT.md b/deps/rabbitmq_amqp1_0/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/CODE_OF_CONDUCT.md rename to deps/rabbitmq_amqp1_0/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/CONTRIBUTING.md b/deps/rabbitmq_amqp1_0/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/CONTRIBUTING.md rename to deps/rabbitmq_amqp1_0/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/Makefile b/deps/rabbitmq_amqp1_0/Makefile similarity index 75% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/Makefile rename to deps/rabbitmq_amqp1_0/Makefile index 072fb6a..e320af4 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/Makefile +++ b/deps/rabbitmq_amqp1_0/Makefile @@ -1,19 +1,8 @@ PROJECT = rabbitmq_amqp1_0 -PROJECT_DESCRIPTION = AMQP 1.0 support for RabbitMQ -define PROJECT_ENV -[ - {default_user, "guest"}, - {default_vhost, <<"/">>}, - {protocol_strict_mode, false} - ] -endef - -BUILD_DEPS = rabbitmq_codegen DEPS = rabbit_common rabbit amqp_client -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers +TEST_DEPS = rabbitmq_ct_helpers -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk EXTRA_SOURCES += include/rabbit_amqp1_0_framing.hrl \ @@ -39,10 +28,8 @@ PYTHON ?= python CODEGEN = $(CURDIR)/codegen.py CODEGEN_DIR ?= $(DEPS_DIR)/rabbitmq_codegen CODEGEN_AMQP = $(CODEGEN_DIR)/amqp_codegen.py -CODEGEN_SPECS = $(CODEGEN_DIR)/amqp-1.0/messaging.xml \ - $(CODEGEN_DIR)/amqp-1.0/security.xml \ - $(CODEGEN_DIR)/amqp-1.0/transport.xml \ - $(CODEGEN_DIR)/amqp-1.0/transactions.xml +CODEGEN_SPECS = spec/messaging.xml spec/security.xml spec/transport.xml \ + spec/transactions.xml include/rabbit_amqp1_0_framing.hrl:: $(CODEGEN) $(CODEGEN_AMQP) \ $(CODEGEN_SPECS) diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/README.md b/deps/rabbitmq_amqp1_0/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/README.md rename to deps/rabbitmq_amqp1_0/README.md diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/codegen.py b/deps/rabbitmq_amqp1_0/codegen.py similarity index 100% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/codegen.py rename to deps/rabbitmq_amqp1_0/codegen.py diff --git a/rabbitmq-server/deps/rabbit/erlang.mk b/deps/rabbitmq_amqp1_0/erlang.mk similarity index 92% rename from rabbitmq-server/deps/rabbit/erlang.mk rename to deps/rabbitmq_amqp1_0/erlang.mk index 89ba561..6d2a31c 100644 --- a/rabbitmq-server/deps/rabbit/erlang.mk +++ b/deps/rabbitmq_amqp1_0/erlang.mk @@ -1,4 +1,4 @@ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # # Permission to use, copy, modify, and/or distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -12,23 +12,11 @@ # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -.PHONY: all app apps deps search rel relup docs install-docs check tests clean distclean help erlang-mk +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) -export ERLANG_MK_FILENAME - -ERLANG_MK_VERSION = 2.0.0-pre.2-256-g2cce185 -ERLANG_MK_WITHOUT = - -# Make 3.81 and 3.82 are deprecated. - -ifeq ($(MAKE_VERSION),3.81) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif -ifeq ($(MAKE_VERSION),3.82) -$(warning Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html) -endif +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 # Core configuration. @@ -37,7 +25,6 @@ PROJECT := $(strip $(PROJECT)) PROJECT_VERSION ?= rolling PROJECT_MOD ?= $(PROJECT)_app -PROJECT_ENV ?= [] # Verbosity. @@ -98,8 +85,6 @@ all:: deps app rel rel:: $(verbose) : -relup:: deps app - check:: tests clean:: clean-crashdump @@ -117,7 +102,7 @@ distclean-tmp: help:: $(verbose) printf "%s\n" \ "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ - "Copyright (c) 2013-2016 Loïc Hoguin " \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ "" \ "Usage: [V=1] $(MAKE) [target]..." \ "" \ @@ -165,7 +150,30 @@ else core_native_path = $1 endif -core_http_get = curl -Lf$(if $(filter-out 0,$(V)),,s)o $(call core_native_path,$1) $2 +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) @@ -185,14 +193,13 @@ ERLANG_MK_COMMIT ?= ERLANG_MK_BUILD_CONFIG ?= build.config ERLANG_MK_BUILD_DIR ?= .erlang.mk.build -erlang-mk: WITHOUT ?= $(ERLANG_MK_WITHOUT) erlang-mk: git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) ifdef ERLANG_MK_COMMIT cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) endif if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi - $(MAKE) -C $(ERLANG_MK_BUILD_DIR) WITHOUT='$(strip $(WITHOUT))' + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk rm -rf $(ERLANG_MK_BUILD_DIR) @@ -279,14 +286,6 @@ pkg_apns_fetch = git pkg_apns_repo = https://github.com/inaka/apns4erl pkg_apns_commit = master -PACKAGES += asciideck -pkg_asciideck_name = asciideck -pkg_asciideck_description = Asciidoc for Erlang. -pkg_asciideck_homepage = https://ninenines.eu -pkg_asciideck_fetch = git -pkg_asciideck_repo = https://github.com/ninenines/asciideck -pkg_asciideck_commit = master - PACKAGES += azdht pkg_azdht_name = azdht pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang @@ -407,14 +406,6 @@ pkg_bootstrap_fetch = git pkg_bootstrap_repo = https://github.com/schlagert/bootstrap pkg_bootstrap_commit = master -PACKAGES += boss -pkg_boss_name = boss -pkg_boss_description = Erlang web MVC, now featuring Comet -pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_fetch = git -pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss -pkg_boss_commit = master - PACKAGES += boss_db pkg_boss_db_name = boss_db pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang @@ -423,6 +414,14 @@ pkg_boss_db_fetch = git pkg_boss_db_repo = https://github.com/ErlyORM/boss_db pkg_boss_db_commit = master +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + PACKAGES += brod pkg_brod_name = brod pkg_brod_description = Kafka client in Erlang @@ -567,13 +566,13 @@ pkg_cloudi_service_api_requests_fetch = git pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests pkg_cloudi_service_api_requests_commit = master -PACKAGES += cloudi_service_db -pkg_cloudi_service_db_name = cloudi_service_db -pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) -pkg_cloudi_service_db_homepage = http://cloudi.org/ -pkg_cloudi_service_db_fetch = git -pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db -pkg_cloudi_service_db_commit = master +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master PACKAGES += cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra @@ -583,14 +582,6 @@ pkg_cloudi_service_db_cassandra_fetch = git pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra pkg_cloudi_service_db_cassandra_commit = master -PACKAGES += cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service -pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ -pkg_cloudi_service_db_cassandra_cql_fetch = git -pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql -pkg_cloudi_service_db_cassandra_cql_commit = master - PACKAGES += cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service @@ -647,6 +638,14 @@ pkg_cloudi_service_db_tokyotyrant_fetch = git pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant pkg_cloudi_service_db_tokyotyrant_commit = master +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + PACKAGES += cloudi_service_filesystem pkg_cloudi_service_filesystem_name = cloudi_service_filesystem pkg_cloudi_service_filesystem_description = Filesystem CloudI Service @@ -1039,14 +1038,6 @@ pkg_edown_fetch = git pkg_edown_repo = https://github.com/uwiger/edown pkg_edown_commit = master -PACKAGES += eep -pkg_eep_name = eep -pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy -pkg_eep_homepage = https://github.com/virtan/eep -pkg_eep_fetch = git -pkg_eep_repo = https://github.com/virtan/eep -pkg_eep_commit = master - PACKAGES += eep_app pkg_eep_app_name = eep_app pkg_eep_app_description = Embedded Event Processing @@ -1055,6 +1046,14 @@ pkg_eep_app_fetch = git pkg_eep_app_repo = https://github.com/darach/eep-erl pkg_eep_app_commit = master +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + PACKAGES += efene pkg_efene_name = efene pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX @@ -1239,14 +1238,6 @@ pkg_eqm_fetch = git pkg_eqm_repo = https://github.com/loucash/eqm pkg_eqm_commit = master -PACKAGES += eredis -pkg_eredis_name = eredis -pkg_eredis_description = Erlang Redis client -pkg_eredis_homepage = https://github.com/wooga/eredis -pkg_eredis_fetch = git -pkg_eredis_repo = https://github.com/wooga/eredis -pkg_eredis_commit = master - PACKAGES += eredis_pool pkg_eredis_pool_name = eredis_pool pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. @@ -1255,6 +1246,14 @@ pkg_eredis_pool_fetch = git pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool pkg_eredis_pool_commit = master +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + PACKAGES += erl_streams pkg_erl_streams_name = erl_streams pkg_erl_streams_description = Streams in Erlang @@ -1543,14 +1542,6 @@ pkg_etap_fetch = git pkg_etap_repo = https://github.com/ngerakines/etap pkg_etap_commit = master -PACKAGES += etest -pkg_etest_name = etest -pkg_etest_description = A lightweight, convention over configuration test framework for Erlang -pkg_etest_homepage = https://github.com/wooga/etest -pkg_etest_fetch = git -pkg_etest_repo = https://github.com/wooga/etest -pkg_etest_commit = master - PACKAGES += etest_http pkg_etest_http_name = etest_http pkg_etest_http_description = etest Assertions around HTTP (client-side) @@ -1559,6 +1550,14 @@ pkg_etest_http_fetch = git pkg_etest_http_repo = https://github.com/wooga/etest_http pkg_etest_http_commit = master +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + PACKAGES += etoml pkg_etoml_name = etoml pkg_etoml_description = TOML language erlang parser @@ -1567,14 +1566,6 @@ pkg_etoml_fetch = git pkg_etoml_repo = https://github.com/kalta/etoml pkg_etoml_commit = master -PACKAGES += eunit -pkg_eunit_name = eunit -pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. -pkg_eunit_homepage = https://github.com/richcarl/eunit -pkg_eunit_fetch = git -pkg_eunit_repo = https://github.com/richcarl/eunit -pkg_eunit_commit = master - PACKAGES += eunit_formatters pkg_eunit_formatters_name = eunit_formatters pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. @@ -1583,6 +1574,14 @@ pkg_eunit_formatters_fetch = git pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters pkg_eunit_formatters_commit = master +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + PACKAGES += euthanasia pkg_euthanasia_name = euthanasia pkg_euthanasia_description = Merciful killer for your Erlang processes @@ -1600,7 +1599,7 @@ pkg_evum_repo = https://github.com/msantos/evum pkg_evum_commit = master PACKAGES += exec -pkg_exec_name = erlexec +pkg_exec_name = exec pkg_exec_description = Execute and control OS processes from Erlang/OTP. pkg_exec_homepage = http://saleyn.github.com/erlexec pkg_exec_fetch = git @@ -1719,14 +1718,6 @@ pkg_fn_fetch = git pkg_fn_repo = https://github.com/reiddraper/fn pkg_fn_commit = master -PACKAGES += folsom -pkg_folsom_name = folsom -pkg_folsom_description = Expose Erlang Events and Metrics -pkg_folsom_homepage = https://github.com/boundary/folsom -pkg_folsom_fetch = git -pkg_folsom_repo = https://github.com/boundary/folsom -pkg_folsom_commit = master - PACKAGES += folsom_cowboy pkg_folsom_cowboy_name = folsom_cowboy pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. @@ -1735,6 +1726,14 @@ pkg_folsom_cowboy_fetch = git pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy pkg_folsom_cowboy_commit = master +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + PACKAGES += folsomite pkg_folsomite_name = folsomite pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics @@ -2095,14 +2094,6 @@ pkg_jesse_fetch = git pkg_jesse_repo = https://github.com/for-GET/jesse pkg_jesse_commit = master -PACKAGES += jiffy -pkg_jiffy_name = jiffy -pkg_jiffy_description = JSON NIFs for Erlang. -pkg_jiffy_homepage = https://github.com/davisp/jiffy -pkg_jiffy_fetch = git -pkg_jiffy_repo = https://github.com/davisp/jiffy -pkg_jiffy_commit = master - PACKAGES += jiffy_v pkg_jiffy_v_name = jiffy_v pkg_jiffy_v_description = JSON validation utility @@ -2111,6 +2102,14 @@ pkg_jiffy_v_fetch = git pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v pkg_jiffy_v_commit = master +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + PACKAGES += jobs pkg_jobs_name = jobs pkg_jobs_description = a Job scheduler for load regulation @@ -2127,14 +2126,6 @@ pkg_joxa_fetch = git pkg_joxa_repo = https://github.com/joxa/joxa pkg_joxa_commit = master -PACKAGES += json -pkg_json_name = json -pkg_json_description = a high level json library for erlang (17.0+) -pkg_json_homepage = https://github.com/talentdeficit/json -pkg_json_fetch = git -pkg_json_repo = https://github.com/talentdeficit/json -pkg_json_commit = master - PACKAGES += json_rec pkg_json_rec_name = json_rec pkg_json_rec_description = JSON to erlang record @@ -2143,6 +2134,14 @@ pkg_json_rec_fetch = git pkg_json_rec_repo = https://github.com/justinkirby/json_rec pkg_json_rec_commit = master +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + PACKAGES += jsone pkg_jsone_name = jsone pkg_jsone_description = An Erlang library for encoding, decoding JSON data. @@ -2183,14 +2182,6 @@ pkg_jsx_fetch = git pkg_jsx_repo = https://github.com/talentdeficit/jsx pkg_jsx_commit = master -PACKAGES += kafka -pkg_kafka_name = kafka -pkg_kafka_description = Kafka consumer and producer in Erlang -pkg_kafka_homepage = https://github.com/wooga/kafka-erlang -pkg_kafka_fetch = git -pkg_kafka_repo = https://github.com/wooga/kafka-erlang -pkg_kafka_commit = master - PACKAGES += kafka_protocol pkg_kafka_protocol_name = kafka_protocol pkg_kafka_protocol_description = Kafka protocol Erlang library @@ -2199,6 +2190,14 @@ pkg_kafka_protocol_fetch = git pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git pkg_kafka_protocol_commit = master +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + PACKAGES += kai pkg_kai_name = kai pkg_kai_description = DHT storage by Takeshi Inoue @@ -2295,14 +2294,6 @@ pkg_kvs_fetch = git pkg_kvs_repo = https://github.com/synrc/kvs pkg_kvs_commit = master -PACKAGES += lager -pkg_lager_name = lager -pkg_lager_description = A logging framework for Erlang/OTP. -pkg_lager_homepage = https://github.com/basho/lager -pkg_lager_fetch = git -pkg_lager_repo = https://github.com/basho/lager -pkg_lager_commit = master - PACKAGES += lager_amqp_backend pkg_lager_amqp_backend_name = lager_amqp_backend pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend @@ -2319,6 +2310,14 @@ pkg_lager_syslog_fetch = git pkg_lager_syslog_repo = https://github.com/basho/lager_syslog pkg_lager_syslog_commit = master +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + PACKAGES += lambdapad pkg_lambdapad_name = lambdapad pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. @@ -2575,14 +2574,6 @@ pkg_mixer_fetch = git pkg_mixer_repo = https://github.com/chef/mixer pkg_mixer_commit = master -PACKAGES += mochiweb -pkg_mochiweb_name = mochiweb -pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. -pkg_mochiweb_homepage = https://github.com/mochi/mochiweb -pkg_mochiweb_fetch = git -pkg_mochiweb_repo = https://github.com/mochi/mochiweb -pkg_mochiweb_commit = master - PACKAGES += mochiweb_xpath pkg_mochiweb_xpath_name = mochiweb_xpath pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser @@ -2591,6 +2582,14 @@ pkg_mochiweb_xpath_fetch = git pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath pkg_mochiweb_xpath_commit = master +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + PACKAGES += mockgyver pkg_mockgyver_name = mockgyver pkg_mockgyver_description = A mocking library for Erlang @@ -3063,14 +3062,6 @@ pkg_quickrand_fetch = git pkg_quickrand_repo = https://github.com/okeuday/quickrand pkg_quickrand_commit = master -PACKAGES += rabbit -pkg_rabbit_name = rabbit -pkg_rabbit_description = RabbitMQ Server -pkg_rabbit_homepage = https://www.rabbitmq.com/ -pkg_rabbit_fetch = git -pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git -pkg_rabbit_commit = master - PACKAGES += rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak @@ -3079,6 +3070,14 @@ pkg_rabbit_exchange_type_riak_fetch = git pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange pkg_rabbit_exchange_type_riak_commit = master +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + PACKAGES += rack pkg_rack_name = rack pkg_rack_description = Rack handler for erlang @@ -3495,14 +3494,6 @@ pkg_smother_fetch = git pkg_smother_repo = https://github.com/ramsay-t/Smother pkg_smother_commit = master -PACKAGES += snappyer -pkg_snappyer_name = snappyer -pkg_snappyer_description = Snappy as nif for Erlang -pkg_snappyer_homepage = https://github.com/zmstone/snappyer -pkg_snappyer_fetch = git -pkg_snappyer_repo = https://github.com/zmstone/snappyer.git -pkg_snappyer_commit = master - PACKAGES += social pkg_social_name = social pkg_social_description = Cowboy handler for social login via OAuth2 providers @@ -3551,14 +3542,6 @@ pkg_stable_fetch = git pkg_stable_repo = https://github.com/dvv/stable pkg_stable_commit = master -PACKAGES += statebox -pkg_statebox_name = statebox -pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. -pkg_statebox_homepage = https://github.com/mochi/statebox -pkg_statebox_fetch = git -pkg_statebox_repo = https://github.com/mochi/statebox -pkg_statebox_commit = master - PACKAGES += statebox_riak pkg_statebox_riak_name = statebox_riak pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. @@ -3567,6 +3550,14 @@ pkg_statebox_riak_fetch = git pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak pkg_statebox_riak_commit = master +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + PACKAGES += statman pkg_statman_name = statman pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM @@ -3735,14 +3726,6 @@ pkg_tirerl_fetch = git pkg_tirerl_repo = https://github.com/inaka/tirerl pkg_tirerl_commit = master -PACKAGES += toml -pkg_toml_name = toml -pkg_toml_description = TOML (0.4.0) config parser -pkg_toml_homepage = http://dozzie.jarowit.net/trac/wiki/TOML -pkg_toml_fetch = git -pkg_toml_repo = https://github.com/dozzie/toml -pkg_toml_commit = v0.2.0 - PACKAGES += traffic_tools pkg_traffic_tools_name = traffic_tools pkg_traffic_tools_description = Simple traffic limiting library @@ -4079,7 +4062,7 @@ pkg_zucchini_fetch = git pkg_zucchini_repo = https://github.com/devinus/zucchini pkg_zucchini_commit = master -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: search @@ -4106,10 +4089,10 @@ else $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-deps clean-tmp-deps.log +.PHONY: distclean-deps # Configuration. @@ -4129,32 +4112,11 @@ export DEPS_DIR REBAR_DEPS_DIR = $(DEPS_DIR) export REBAR_DEPS_DIR -# External "early" plugins (see core/plugins.mk for regular plugins). -# They both use the core_dep_plugin macro. - -define core_dep_plugin -ifeq ($(2),$(PROJECT)) --include $$(patsubst $(PROJECT)/%,%,$(1)) -else --include $(DEPS_DIR)/$(1) - -$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; -endif -endef - -DEP_EARLY_PLUGINS ?= - -$(foreach p,$(DEP_EARLY_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/early-plugins.mk,$p)))) - dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) -LOCAL_DEPS_DIRS = $(foreach a,$(LOCAL_DEPS),$(if $(wildcard $(APPS_DIR)/$(a)),$(APPS_DIR)/$(a))) ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) @@ -4177,7 +4139,10 @@ dep_verbose = $(dep_verbose_$(V)) # Core targets. -apps:: $(ALL_APPS_DIRS) clean-tmp-deps.log +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log endif @@ -4185,42 +4150,36 @@ endif # Create ebin directory for all apps to make sure Erlang recognizes them # as proper OTP applications when using -include_lib. This is a temporary # fix, a proper fix would be to compile apps/* in the right order. -ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - mkdir -p $$dep/ebin; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ done -endif -# at the toplevel: if LOCAL_DEPS is defined with at least one local app, only -# compile that list of apps. otherwise, compile everything. -# within an app: compile all LOCAL_DEPS that are (uncompiled) local apps - $(verbose) set -e; for dep in $(if $(LOCAL_DEPS_DIRS)$(IS_APP),$(LOCAL_DEPS_DIRS),$(ALL_APPS_DIRS)) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ - $(MAKE) -C $$dep IS_APP=1; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ fi \ done - -clean-tmp-deps.log: -ifeq ($(IS_APP)$(IS_DEP),) - $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log endif ifneq ($(SKIP_DEPS),) deps:: else -deps:: $(ALL_DEPS_DIRS) apps clean-tmp-deps.log +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) set -e; for dep in $(ALL_DEPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ :; \ else \ echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ - $(MAKE) -C $$dep IS_DEP=1; \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ else \ - echo "Error: No Makefile to build dependency $$dep." >&2; \ + echo "Error: No Makefile to build dependency $$dep."; \ exit 2; \ fi \ fi \ @@ -4234,18 +4193,17 @@ endif # in practice only Makefile is needed so far. define dep_autopatch if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ - rm -rf $(DEPS_DIR)/$1/ebin/; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ $(call dep_autopatch_erlang_mk,$(1)); \ elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ - if [ -f $(DEPS_DIR)/$1/rebar.lock ]; then \ - $(call dep_autopatch2,$1); \ - elif [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ 0 != `grep -ci "^[^#].*rebar" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ $(call dep_autopatch2,$(1)); \ - elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i "^[^#].*rebar" '{}' \;`" ]; then \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ fi \ else \ if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ @@ -4257,14 +4215,11 @@ define dep_autopatch endef define dep_autopatch2 - ! test -f $(DEPS_DIR)/$1/ebin/$1.app || \ - mv -n $(DEPS_DIR)/$1/ebin/$1.app $(DEPS_DIR)/$1/src/$1.app.src; \ - rm -f $(DEPS_DIR)/$1/ebin/$1.app; \ if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ fi; \ $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ - if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script -o -f $(DEPS_DIR)/$1/rebar.lock ]; then \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ $(call dep_autopatch_fetch_rebar); \ $(call dep_autopatch_rebar,$(1)); \ else \ @@ -4276,15 +4231,11 @@ define dep_autopatch_noop printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile endef -# Replace "include erlang.mk" with a line that will load the parent Erlang.mk -# if given. Do it for all 3 possible Makefile file names. +# Overwrite erlang.mk with the current file by default. ifeq ($(NO_AUTOPATCH_ERLANG_MK),) define dep_autopatch_erlang_mk - $t for f in Makefile makefile GNUmakefile; do \ - if [ -f $(DEPS_DIR)/$1/$$f ]; then \ - sed -i.bak s/'include *erlang.mk'/'include $$(if $$(ERLANG_MK_FILENAME),$$(ERLANG_MK_FILENAME),erlang.mk)'/ $(DEPS_DIR)/$1/$$f; \ - fi \ - done + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk endef else define dep_autopatch_erlang_mk @@ -4303,7 +4254,7 @@ define dep_autopatch_fetch_rebar if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ cd $(ERLANG_MK_TMP)/rebar; \ - git checkout -q 576e12171ab8d69b048b827b92aa65d067deea01; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ $(MAKE); \ cd -; \ fi @@ -4320,7 +4271,6 @@ endef define dep_autopatch_rebar.erl application:load(rebar), application:set_env(rebar, log_level, debug), - rmemo:start(), Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of {ok, Conf0} -> Conf0; _ -> [] @@ -4474,9 +4424,9 @@ define dep_autopatch_rebar.erl [] -> ok; _ -> Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), - PortSpecWrite(io_lib:format("ERL_CFLAGS ?= -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), - PortSpecWrite(io_lib:format("ERL_LDFLAGS ?= -L \\"~s\\" -lerl_interface -lei\n", + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", [code:lib_dir(erl_interface, lib)])), [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], FilterEnv = fun(Env) -> @@ -4515,7 +4465,7 @@ define dep_autopatch_rebar.erl "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", - [[Output, ": ", K, " += ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], Output, ": $$\(foreach ext,.c .C .cc .cpp,", "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", @@ -4527,7 +4477,7 @@ define dep_autopatch_rebar.erl end, [PortSpec(S) || S <- PortSpecs] end, - Write("\ninclude $$\(if $$\(ERLANG_MK_FILENAME),$$\(ERLANG_MK_FILENAME),erlang.mk)"), + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), RunPlugin = fun(Plugin, Step) -> case erlang:function_exported(Plugin, Step, 2) of false -> ok; @@ -4575,6 +4525,22 @@ define dep_autopatch_rebar.erl halt() endef +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + define dep_autopatch_appsrc_script.erl AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", AppSrcScript = AppSrc ++ ".script", @@ -4622,16 +4588,21 @@ define dep_fetch_cp cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); endef -define dep_fetch_ln - ln -s $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() endef # Hex only has a package version. No need to look in the Erlang.mk packages. define dep_fetch_hex - mkdir -p $(ERLANG_MK_TMP)/hex $(DEPS_DIR)/$1; \ - $(call core_http_get,$(ERLANG_MK_TMP)/hex/$1.tar,\ - https://s3.amazonaws.com/s3.hex.pm/tarballs/$1-$(strip $(word 2,$(dep_$1))).tar); \ - tar -xOf $(ERLANG_MK_TMP)/hex/$1.tar contents.tar.gz | tar -C $(DEPS_DIR)/$1 -xzf -; + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); endef define dep_fetch_fail @@ -4661,7 +4632,7 @@ $(DEPS_DIR)/$(call dep_name,$1): $(eval DEP_NAME := $(call dep_name,$1)) $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ - echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)." >&2; \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ exit 17; \ fi $(verbose) mkdir -p $(DEPS_DIR) @@ -4703,15 +4674,15 @@ ifndef IS_APP clean:: clean-apps clean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep clean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ done distclean:: distclean-apps distclean-apps: - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ - $(MAKE) -C $$dep distclean IS_APP=1; \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ done endif @@ -4731,7 +4702,85 @@ ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log -# Copyright (c) 2015-2016, Loïc Hoguin +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. # Verbosity. @@ -4750,9 +4799,10 @@ endef define compile_proto.erl [begin + Dir = filename:dirname(filename:dirname(F)), protobuffs_compile:generate_source(F, - [{output_include_dir, "./include"}, - {output_src_dir, "./ebin"}]) + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) end || F <- string:tokens("$(1)", " ")], halt(). endef @@ -4762,7 +4812,7 @@ ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) $(if $(strip $?),$(call compile_proto,$?)) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-app @@ -4776,8 +4826,6 @@ COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) ERLC_EXCLUDE ?= ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) -ERLC_ASN1_OPTS ?= - ERLC_MIB_OPTS ?= COMPILE_MIB_FIRST ?= COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) @@ -4827,27 +4875,25 @@ endif ifeq ($(wildcard src/$(PROJECT_MOD).erl),) define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, []}, - {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} ]}. endef else define app_file -{application, '$(PROJECT)', [ +{application, $(PROJECT), [ {description, "$(PROJECT_DESCRIPTION)"}, {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), {id$(comma)$(space)"$(1)"}$(comma)) {modules, [$(call comma_list,$(2))]}, {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, - {mod, {$(PROJECT_MOD), []}}, - {env, $(subst \,\\,$(PROJECT_ENV))}$(if $(findstring {,$(PROJECT_APP_EXTRA_KEYS)),$(comma)$(newline)$(tab)$(subst \,\\,$(PROJECT_APP_EXTRA_KEYS)),) + {mod, {$(PROJECT_MOD), []}} ]}. endef endif @@ -4857,10 +4903,8 @@ app-build: ebin/$(PROJECT).app # Source files. -ALL_SRC_FILES := $(sort $(call core_find,src/,*)) - -ERL_FILES := $(filter %.erl,$(ALL_SRC_FILES)) -CORE_FILES := $(filter %.core,$(ALL_SRC_FILES)) +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) # ASN.1 files. @@ -4870,7 +4914,7 @@ ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) define compile_asn1 $(verbose) mkdir -p include/ - $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(ERLC_ASN1_OPTS) $(1) + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) $(verbose) mv asn1/*.erl src/ $(verbose) mv asn1/*.hrl include/ $(verbose) mv asn1/*.asn1db include/ @@ -4893,16 +4937,16 @@ endif # Leex and Yecc files. -XRL_FILES := $(filter %.xrl,$(ALL_SRC_FILES)) +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) ERL_FILES += $(XRL_ERL_FILES) -YRL_FILES := $(filter %.yrl,$(ALL_SRC_FILES)) +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) ERL_FILES += $(YRL_ERL_FILES) $(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) - $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $(YRL_ERLC_OPTS) $?) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) # Erlang and Core Erlang files. @@ -4952,12 +4996,7 @@ define makedep.erl (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); (F, Mod, import, {Imp, _}) -> - IsFile = - case lists:keyfind(Imp, 1, Modules) of - false -> false; - {_, FilePath} -> filelib:is_file(FilePath) - end, - case IsFile of + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of false -> ok; true -> Add(Mod, Imp) end; @@ -4981,17 +5020,9 @@ define makedep.erl end || F <- ErlFiles], Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], - TargetPath = fun(Target) -> - case lists:keyfind(Target, 1, Modules) of - false -> ""; - {_, DepFile} -> - DirSubname = tl(string:tokens(filename:dirname(DepFile), "/")), - string:join(DirSubname ++ [atom_to_list(Target)], "/") - end - end, ok = file:write_file("$(1)", [ [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], - "\nCOMPILE_FIRST +=", [[" ", TargetPath(CF)] || CF <- CompileFirst], "\n" + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" ]), halt() endef @@ -5004,18 +5035,18 @@ endif ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) # Rebuild everything when the Makefile changes. $(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(verbose) if test -f $@; then \ + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ touch -c $(PROJECT).d; \ fi - $(verbose) touch $@ + @touch $@ $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change endif -include $(wildcard $(PROJECT).d) +-include $(PROJECT).d ebin/$(PROJECT).app:: ebin/ @@ -5034,7 +5065,7 @@ ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.s $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) ifeq ($(wildcard src/$(PROJECT).app.src),) - $(app_verbose) printf '$(subst %,%%,$(subst $(newline),\n,$(subst ','\'',$(call app_file,$(GITDESCRIBE),$(MODULES)))))' \ + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ > ebin/$(PROJECT).app else $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ @@ -5058,7 +5089,6 @@ clean-app: endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -5076,10 +5106,10 @@ ifneq ($(SKIP_DEPS),) doc-deps: else doc-deps: $(ALL_DOC_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rel-deps @@ -5096,10 +5126,10 @@ ifneq ($(SKIP_DEPS),) rel-deps: else rel-deps: $(ALL_REL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: test-deps test-dir test-build clean-test-dir @@ -5121,7 +5151,7 @@ ifneq ($(SKIP_DEPS),) test-deps: else test-deps: $(ALL_TEST_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done endif ifneq ($(wildcard $(TEST_DIR)),) @@ -5154,7 +5184,7 @@ ifneq ($(wildcard $(TEST_DIR)/*.beam),) endif endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: rebar.config @@ -5190,90 +5220,54 @@ $(eval export _compat_rebar_config) rebar.config: $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -ifeq ($(filter asciideck,$(DEPS) $(DOC_DEPS)),asciideck) +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc -.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc-guide distclean-asciidoc-manual - -# Core targets. +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 docs:: asciidoc -distclean:: distclean-asciidoc-guide distclean-asciidoc-manual - -# Plugin-specific targets. - asciidoc: asciidoc-guide asciidoc-manual -# User guide. - ifeq ($(wildcard doc/src/guide/book.asciidoc),) asciidoc-guide: else -asciidoc-guide: distclean-asciidoc-guide doc-deps +asciidoc-guide: distclean-asciidoc doc-deps a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ - -distclean-asciidoc-guide: - $(gen_verbose) rm -rf doc/html/ doc/guide.pdf endif -# Man pages. - -ASCIIDOC_MANUAL_FILES := $(wildcard doc/src/manual/*.asciidoc) - -ifeq ($(ASCIIDOC_MANUAL_FILES),) +ifeq ($(wildcard doc/src/manual/*.asciidoc),) asciidoc-manual: else - -# Configuration. - -MAN_INSTALL_PATH ?= /usr/local/share/man -MAN_SECTIONS ?= 3 7 -MAN_PROJECT ?= $(shell echo $(PROJECT) | sed 's/^./\U&\E/') -MAN_VERSION ?= $(PROJECT_VERSION) - -# Plugin-specific targets. - -define asciidoc2man.erl -try - [begin - io:format(" ADOC ~s~n", [F]), - ok = asciideck:to_manpage(asciideck:parse_file(F), #{ - compress => gzip, - outdir => filename:dirname(F), - extra2 => "$(MAN_PROJECT) $(MAN_VERSION)", - extra3 => "$(MAN_PROJECT) Function Reference" - }) - end || F <- [$(shell echo $(addprefix $(comma)\",$(addsuffix \",$1)) | sed 's/^.//')]], - halt(0) -catch C:E -> - io:format("Exception ~p:~p~nStacktrace: ~p~n", [C, E, erlang:get_stacktrace()]), - halt(1) -end. -endef - -asciidoc-manual:: doc-deps - -asciidoc-manual:: $(ASCIIDOC_MANUAL_FILES) - $(call erlang,$(call asciidoc2man.erl,$?)) - $(foreach s,$(MAN_SECTIONS),mkdir -p doc/man$s/ && mv doc/src/manual/*.$s.gz doc/man$s/;) +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done install-docs:: install-asciidoc install-asciidoc: asciidoc-manual - $(foreach s,$(MAN_SECTIONS),\ - mkdir -p $(MAN_INSTALL_PATH)/man$s/ && \ - install -g `id -u` -o `id -g` -m 0644 doc/man$s/*.gz $(MAN_INSTALL_PATH)/man$s/;) - -distclean-asciidoc-manual: - $(gen_verbose) rm -rf $(addprefix doc/man,$(MAN_SECTIONS)) -endif + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done endif -# Copyright (c) 2014-2016, Loïc Hoguin +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates @@ -5330,7 +5324,7 @@ ifdef SP define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 # Whitespace to be used when creating files from templates. SP = $(SP) @@ -5340,7 +5334,7 @@ else define bs_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 endef endif @@ -5348,7 +5342,7 @@ endif define bs_apps_Makefile PROJECT = $p PROJECT_DESCRIPTION = New project -PROJECT_VERSION = 0.1.0 +PROJECT_VERSION = 0.0.1 include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk endef @@ -5368,7 +5362,7 @@ stop(_State) -> endef define bs_relx_config -{release, {$p_release, "1"}, [$p, sasl, runtime_tools]}. +{release, {$p_release, "1"}, [$p]}. {extended_start_script, true}. {sys_config, "rel/sys.config"}. {vm_args, "rel/vm.args"}. @@ -5719,6 +5713,9 @@ endif ifndef t $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif +ifndef tpl_$(t) + $(error Unknown template) +endif ifndef n $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) endif @@ -5731,7 +5728,7 @@ endif list-templates: $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) -# Copyright (c) 2014-2016, Loïc Hoguin +# Copyright (c) 2014-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: clean-c_src distclean-c_src-env @@ -5966,94 +5963,56 @@ else $(call render_template,bs_erl_nif,src/$n.erl) endif -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: ci ci-prepare ci-setup distclean-kerl - -CI_OTP ?= -CI_HIPE ?= -CI_ERLLVM ?= - -ifeq ($(CI_VM),native) -ERLC_OPTS += +native -TEST_ERLC_OPTS += +native -else ifeq ($(CI_VM),erllvm) -ERLC_OPTS += +native +'{hipe, [to_llvm]}' -TEST_ERLC_OPTS += +native +'{hipe, [to_llvm]}' -endif - -ifeq ($(strip $(CI_OTP) $(CI_HIPE) $(CI_ERLLVM)),) -ci:: -else - -ifeq ($(strip $(KERL)),) -KERL := $(ERLANG_MK_TMP)/kerl/kerl -endif +.PHONY: ci ci-setup distclean-kerl +KERL ?= $(CURDIR)/kerl export KERL -KERL_GIT ?= https://github.com/kerl/kerl -KERL_COMMIT ?= master - -KERL_MAKEFLAGS ?= +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl OTP_GIT ?= https://github.com/erlang/otp CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= -ci:: $(addprefix ci-,$(CI_OTP) $(addsuffix -native,$(CI_HIPE)) $(addsuffix -erllvm,$(CI_ERLLVM))) +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) -ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP) $(addsuffix -native,$(CI_HIPE))) +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) ci-setup:: -ci-extra:: - ci_verbose_0 = @echo " CI " $(1); ci_verbose = $(ci_verbose_$(V)) define ci_target -ci-$1: $(CI_INSTALL_DIR)/$2 - $(verbose) $(MAKE) --no-print-directory clean +ci-$(1): $(CI_INSTALL_DIR)/$(1) $(ci_verbose) \ - PATH="$(CI_INSTALL_DIR)/$2/bin:$(PATH)" \ - CI_OTP_RELEASE="$1" \ - CT_OPTS="-label $1" \ - CI_VM="$3" \ - $(MAKE) ci-setup tests - $(verbose) $(MAKE) --no-print-directory ci-extra + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests endef -$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp),$(otp),otp))) -$(foreach otp,$(CI_HIPE),$(eval $(call ci_target,$(otp)-native,$(otp)-native,native))) -$(foreach otp,$(CI_ERLLVM),$(eval $(call ci_target,$(otp)-erllvm,$(otp)-native,erllvm))) +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) define ci_otp_target ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) $(CI_INSTALL_DIR)/$(1): $(KERL) - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) build git $(OTP_GIT) $(1) $(1) $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) endif endef $(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) -define ci_hipe_target -ifeq ($(wildcard $(CI_INSTALL_DIR)/$1-native),) -$(CI_INSTALL_DIR)/$1-native: $(KERL) - KERL_CONFIGURE_OPTIONS=--enable-native-libs \ - MAKEFLAGS="$(KERL_MAKEFLAGS)" $(KERL) build git $(OTP_GIT) $1 $1-native - $(KERL) install $1-native $(CI_INSTALL_DIR)/$1-native -endif -endef - -$(foreach otp,$(sort $(CI_HIPE) $(CI_ERLLLVM)),$(eval $(call ci_hipe_target,$(otp)))) - $(KERL): - $(verbose) mkdir -p $(ERLANG_MK_TMP) - $(gen_verbose) git clone --depth 1 $(KERL_GIT) $(ERLANG_MK_TMP)/kerl - $(verbose) cd $(ERLANG_MK_TMP)/kerl && git checkout $(KERL_COMMIT) + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) $(verbose) chmod +x $(KERL) help:: @@ -6070,7 +6029,7 @@ distclean-kerl: $(gen_verbose) rm -rf $(KERL) endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: ct apps-ct distclean-ct @@ -6078,14 +6037,11 @@ endif # Configuration. CT_OPTS ?= - ifneq ($(wildcard $(TEST_DIR)),) -ifndef CT_SUITES -CT_SUITES := $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) -endif + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= endif -CT_SUITES ?= -CT_LOGS_DIR ?= $(CURDIR)/logs # Core targets. @@ -6108,18 +6064,15 @@ CT_RUN = ct_run \ -noinput \ -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ -dir $(TEST_DIR) \ - -logdir $(CT_LOGS_DIR) + -logdir $(CURDIR)/logs ifeq ($(CT_SUITES),) ct: $(if $(IS_APP),,apps-ct) else -# We do not run tests if we are in an apps/* with no test directory. -ifneq ($(IS_APP)$(wildcard $(TEST_DIR)),1) ct: test-build $(if $(IS_APP),,apps-ct) - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) endif -endif ifneq ($(ALL_APPS_DIRS),) define ct_app_target @@ -6145,16 +6098,16 @@ endif define ct_suite_target ct-$(1): test-build - $(verbose) mkdir -p $(CT_LOGS_DIR) + $(verbose) mkdir -p $(CURDIR)/logs/ $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) endef $(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) distclean-ct: - $(gen_verbose) rm -rf $(CT_LOGS_DIR) + $(gen_verbose) rm -rf $(CURDIR)/logs/ -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: plt distclean-plt dialyze @@ -6198,10 +6151,7 @@ define filter_opts.erl endef $(DIALYZER_PLT): deps app - $(eval DEPS_LOG := $(shell test -f $(ERLANG_MK_TMP)/deps.log && \ - while read p; do test -d $$p/ebin && echo $$p/ebin; done <$(ERLANG_MK_TMP)/deps.log)) - $(verbose) dialyzer --build_plt --apps erts kernel stdlib \ - $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS_LOG) + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) plt: $(DIALYZER_PLT) @@ -6215,7 +6165,7 @@ dialyze: $(DIALYZER_PLT) endif $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. .PHONY: distclean-edoc edoc @@ -6223,20 +6173,10 @@ endif # Configuration. EDOC_OPTS ?= -EDOC_SRC_DIRS ?= - -define edoc.erl - SrcPaths = lists:foldl(fun(P, Acc) -> - filelib:wildcard(atom_to_list(P) ++ "/{src,c_src}") ++ Acc - end, [], [$(call comma_list,$(patsubst %,'%',$(EDOC_SRC_DIRS)))]), - DefaultOpts = [{source_path, SrcPaths}, {subpackages, false}], - edoc:application($(1), ".", [$(2)] ++ DefaultOpts), - halt(0). -endef # Core targets. -ifneq ($(strip $(EDOC_SRC_DIRS)$(wildcard doc/overview.edoc)),) +ifneq ($(wildcard doc/overview.edoc),) docs:: edoc endif @@ -6245,91 +6185,30 @@ distclean:: distclean-edoc # Plugin-specific targets. edoc: distclean-edoc doc-deps - $(gen_verbose) $(call erlang,$(call edoc.erl,$(PROJECT),$(EDOC_OPTS))) + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' distclean-edoc: $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info -# Copyright (c) 2013-2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# Configuration. - -DTL_FULL_PATH ?= -DTL_PATH ?= templates/ -DTL_SUFFIX ?= _dtl -DTL_OPTS ?= - -# Verbosity. - -dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); -dtl_verbose = $(dtl_verbose_$(V)) - -# Core targets. - -DTL_PATH := $(abspath $(DTL_PATH)) -DTL_FILES := $(sort $(call core_find,$(DTL_PATH),*.dtl)) - -ifneq ($(DTL_FILES),) - -DTL_NAMES = $(addsuffix $(DTL_SUFFIX),$(DTL_FILES:$(DTL_PATH)/%.dtl=%)) -DTL_MODULES = $(if $(DTL_FULL_PATH),$(subst /,_,$(DTL_NAMES)),$(notdir $(DTL_NAMES))) -BEAM_FILES += $(addsuffix .beam,$(addprefix ebin/,$(DTL_MODULES))) - -ifneq ($(words $(DTL_FILES)),0) -# Rebuild templates when the Makefile changes. -$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) - @mkdir -p $(ERLANG_MK_TMP) - @if test -f $@; then \ - touch $(DTL_FILES); \ - fi - @touch $@ - -ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl -endif - -define erlydtl_compile.erl - [begin - Module0 = case "$(strip $(DTL_FULL_PATH))" of - "" -> - filename:basename(F, ".dtl"); - _ -> - "$(DTL_PATH)/" ++ F2 = filename:rootname(F, ".dtl"), - re:replace(F2, "/", "_", [{return, list}, global]) - end, - Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), - case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors]) of - ok -> ok; - {ok, _} -> ok - end - end || F <- string:tokens("$(1)", " ")], - halt(). -endef - -ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ - $(if $(strip $?),\ - $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$(call core_native_path,$?)),\ - -pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) - -endif - -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2014, Dave Cottlehuber +# Copyright (c) 2014 Dave Cottlehuber # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: distclean-escript escript escript-zip +.PHONY: distclean-escript escript # Configuration. ESCRIPT_NAME ?= $(PROJECT) ESCRIPT_FILE ?= $(ESCRIPT_NAME) -ESCRIPT_SHEBANG ?= /usr/bin/env escript ESCRIPT_COMMENT ?= This is an -*- erlang -*- file -ESCRIPT_EMU_ARGS ?= -escript main $(ESCRIPT_NAME) -ESCRIPT_ZIP ?= 7z a -tzip -mx=9 -mtc=off $(if $(filter-out 0,$(V)),,> /dev/null) -ESCRIPT_ZIP_FILE ?= $(ERLANG_MK_TMP)/escript.zip +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" # Core targets. @@ -6342,28 +6221,44 @@ help:: # Plugin-specific targets. -escript-zip:: deps app - $(verbose) mkdir -p $(dir $(ESCRIPT_ZIP)) - $(verbose) rm -f $(ESCRIPT_ZIP_FILE) - $(gen_verbose) cd .. && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) $(PROJECT)/ebin/* -ifneq ($(DEPS),) - $(verbose) cd $(DEPS_DIR) && $(ESCRIPT_ZIP) $(ESCRIPT_ZIP_FILE) \ - `cat $(ERLANG_MK_TMP)/deps.log | sed 's/^$(subst /,\/,$(DEPS_DIR))\///' | sed 's/$$/\/ebin\/\*/'` -endif +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef -escript:: escript-zip - $(gen_verbose) printf "%s\n" \ - "#!$(ESCRIPT_SHEBANG)" \ - "%% $(ESCRIPT_COMMENT)" \ - "%%! $(ESCRIPT_EMU_ARGS)" > $(ESCRIPT_FILE) - $(verbose) cat $(ESCRIPT_ZIP_FILE) >> $(ESCRIPT_FILE) - $(verbose) chmod +x $(ESCRIPT_FILE) +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) distclean-escript: - $(gen_verbose) rm -f $(ESCRIPT_FILE) + $(gen_verbose) rm -f $(ESCRIPT_NAME) -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: eunit apps-eunit @@ -6427,31 +6322,23 @@ eunit: test-build $(if $(IS_APP),,apps-eunit) ifneq ($(ALL_APPS_DIRS),) apps-eunit: - $(verbose) eunit_retcode=0 ; for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; \ - [ $$? -ne 0 ] && eunit_retcode=1 ; done ; \ - exit $$eunit_retcode + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done endif endif -# Copyright (c) 2013-2016, Loïc Hoguin +# Copyright (c) 2013-2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. -.PHONY: relx-rel relx-relup distclean-relx-rel run +.PHONY: relx-rel distclean-relx-rel distclean-relx run # Configuration. -RELX ?= $(ERLANG_MK_TMP)/relx +RELX ?= $(CURDIR)/relx RELX_CONFIG ?= $(CURDIR)/relx.config RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx RELX_OPTS ?= RELX_OUTPUT_DIR ?= _rel -RELX_REL_EXT ?= -RELX_TAR ?= 1 - -ifdef SFX - RELX_TAR = 1 -endif ifeq ($(firstword $(RELX_OPTS)),-o) RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) @@ -6464,12 +6351,10 @@ endif ifeq ($(IS_DEP),) ifneq ($(wildcard $(RELX_CONFIG)),) rel:: relx-rel - -relup:: relx-relup endif endif -distclean:: distclean-relx-rel +distclean:: distclean-relx-rel distclean-relx # Plugin-specific targets. @@ -6478,14 +6363,14 @@ $(RELX): $(verbose) chmod +x $(RELX) relx-rel: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release $(if $(filter 1,$(RELX_TAR)),tar) - -relx-relup: $(RELX) rel-deps app - $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) release relup $(if $(filter 1,$(RELX_TAR)),tar) + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) distclean-relx-rel: $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + # Run target. ifeq ($(wildcard $(RELX_CONFIG)),) @@ -6493,28 +6378,16 @@ run: else define get_relx_release.erl - {ok, Config} = file:consult("$(call core_native_path,$(RELX_CONFIG))"), - {release, {Name, Vsn0}, _} = lists:keyfind(release, 1, Config), - Vsn = case Vsn0 of - {cmd, Cmd} -> os:cmd(Cmd); - semver -> ""; - {semver, _} -> ""; - VsnStr -> Vsn0 - end, - io:format("~s ~s", [Name, Vsn]), + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), halt(0). endef -RELX_REL := $(shell $(call erlang,$(get_relx_release.erl))) -RELX_REL_NAME := $(word 1,$(RELX_REL)) -RELX_REL_VSN := $(word 2,$(RELX_REL)) - -ifeq ($(PLATFORM),msys2) -RELX_REL_EXT := .cmd -endif +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` run: all - $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/bin/$(RELX_REL_NAME)$(RELX_REL_EXT) console + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console help:: $(verbose) printf "%s\n" "" \ @@ -6523,8 +6396,8 @@ help:: endif -# Copyright (c) 2015-2016, Loïc Hoguin # Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin # This file is contributed to erlang.mk and subject to the terms of the ISC License. .PHONY: shell @@ -6549,26 +6422,12 @@ help:: $(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) build-shell-deps: $(ALL_SHELL_DEPS_DIRS) - $(verbose) set -e; for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done shell: build-shell-deps $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) -# Copyright (c) 2017, Jean-Sébastien Pédron -# This file is contributed to erlang.mk and subject to the terms of the ISC License. - -.PHONY: show-ERL_LIBS show-ERLC_OPTS show-TEST_ERLC_OPTS - -show-ERL_LIBS: - @echo $(ERL_LIBS) - -show-ERLC_OPTS: - @$(foreach opt,$(ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -show-TEST_ERLC_OPTS: - @$(foreach opt,$(TEST_ERLC_OPTS) -pa ebin -I include,echo "$(opt)";) - -# Copyright (c) 2015-2016, Loïc Hoguin +# Copyright (c) 2015, Loïc Hoguin # This file is part of erlang.mk and subject to the terms of the ISC License. ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) @@ -6579,7 +6438,7 @@ ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) tests:: triq define triq_check.erl - code:add_pathsa(["$(call core_native_path,$(CURDIR)/ebin)", "$(call core_native_path,$(DEPS_DIR)/*/ebin)"]), + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), try case $(1) of all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); @@ -6611,7 +6470,6 @@ triq: test-build endif endif -# Copyright (c) 2016, Loïc Hoguin # Copyright (c) 2015, Erlang Solutions Ltd. # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6628,14 +6486,14 @@ endif XREFR ?= $(CURDIR)/xrefr export XREFR -XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/1.1.0/xrefr +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr # Core targets. help:: - $(verbose) printf '%s\n' '' \ - 'Xref targets:' \ - ' xref Run Xrefr using $$XREF_CONFIG as config file if defined' + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" distclean:: distclean-xref @@ -6651,8 +6509,7 @@ xref: deps app $(XREFR) distclean-xref: $(gen_verbose) rm -rf $(XREFR) -# Copyright (c) 2016, Loïc Hoguin -# Copyright (c) 2015, Viktor Söderqvist +# Copyright 2015, Viktor Söderqvist # This file is part of erlang.mk and subject to the terms of the ISC License. COVER_REPORT_DIR = cover @@ -6661,7 +6518,6 @@ COVER_REPORT_DIR = cover ifdef COVER ifdef CT_RUN -ifneq ($(wildcard $(TEST_DIR)),) # All modules in 'ebin' COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) @@ -6676,7 +6532,6 @@ $(TEST_DIR)/ct.cover.spec: CT_RUN += -cover $(TEST_DIR)/ct.cover.spec endif endif -endif # Core targets @@ -6698,7 +6553,7 @@ help:: "Cover targets:" \ " cover-report Generate a HTML coverage report from previously collected" \ " cover data." \ - " all.coverdata Merge all coverdata files into all.coverdata." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ "" \ "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ "target tests additionally generates a HTML coverage report from the combined" \ @@ -6711,16 +6566,13 @@ COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) .PHONY: coverdata-clean coverdata-clean: - $(gen_verbose) rm -f *.coverdata $(TEST_DIR)/ct.cover.spec + $(gen_verbose) rm -f *.coverdata ct.cover.spec # Merge all coverdata files into one. -define cover_export.erl - $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) - cover:export("$@"), halt(0). -endef - all.coverdata: $(COVERDATA) - $(gen_verbose) $(call erlang,$(cover_export.erl)) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' # These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to # empty if you want the coverdata files but not the HTML report. @@ -6738,7 +6590,7 @@ else # Modules which include eunit.hrl always contain one line without coverage # because eunit defines test/0 which is never called. We compensate for this. EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ - grep -H -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) define cover_report.erl @@ -6773,71 +6625,12 @@ define cover_report.erl endef cover-report: - $(verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) $(gen_verbose) $(call erlang,$(cover_report.erl)) endif endif # ifneq ($(COVER_REPORT_DIR),) -# Copyright (c) 2016, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -.PHONY: sfx - -ifdef RELX_REL -ifdef SFX - -# Configuration. - -SFX_ARCHIVE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME)/$(RELX_REL_NAME)-$(RELX_REL_VSN).tar.gz -SFX_OUTPUT_FILE ?= $(RELX_OUTPUT_DIR)/$(RELX_REL_NAME).run - -# Core targets. - -rel:: sfx - -# Plugin-specific targets. - -define sfx_stub -#!/bin/sh - -TMPDIR=`mktemp -d` -ARCHIVE=`awk '/^__ARCHIVE_BELOW__$$/ {print NR + 1; exit 0;}' $$0` -FILENAME=$$(basename $$0) -REL=$${FILENAME%.*} - -tail -n+$$ARCHIVE $$0 | tar -xzf - -C $$TMPDIR - -$$TMPDIR/bin/$$REL console -RET=$$? - -rm -rf $$TMPDIR - -exit $$RET - -__ARCHIVE_BELOW__ -endef - -sfx: - $(call render_template,sfx_stub,$(SFX_OUTPUT_FILE)) - $(gen_verbose) cat $(SFX_ARCHIVE) >> $(SFX_OUTPUT_FILE) - $(verbose) chmod +x $(SFX_OUTPUT_FILE) - -endif -endif - -# Copyright (c) 2013-2017, Loïc Hoguin -# This file is part of erlang.mk and subject to the terms of the ISC License. - -# External plugins. - -DEP_PLUGINS ?= - -$(foreach p,$(DEP_PLUGINS),\ - $(eval $(if $(findstring /,$p),\ - $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ - $(call core_dep_plugin,$p/plugins.mk,$p)))) - # Copyright (c) 2013-2015, Loïc Hoguin # Copyright (c) 2015-2016, Jean-Sébastien Pédron # This file is part of erlang.mk and subject to the terms of the ISC License. @@ -6905,20 +6698,22 @@ ifeq ($(IS_APP)$(IS_DEP),) $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) endif ifndef IS_APP - $(verbose) set -e; for dep in $(ALL_APPS_DIRS) ; do \ + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ $(MAKE) -C $$dep $@ \ IS_APP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ done endif - $(verbose) set -e; for dep in $^ ; do \ + $(verbose) for dep in $^ ; do \ if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ - if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk|.*ERLANG_MK_FILENAME.*)$$" \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ $(MAKE) -C $$dep fetch-deps \ IS_DEP=1 \ - ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST); \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ fi \ fi \ done diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/include/rabbit_amqp1_0.hrl b/deps/rabbitmq_amqp1_0/include/rabbit_amqp1_0.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/include/rabbit_amqp1_0.hrl rename to deps/rabbitmq_amqp1_0/include/rabbit_amqp1_0.hrl diff --git a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-components.mk b/deps/rabbitmq_amqp1_0/rabbitmq-components.mk similarity index 83% rename from rabbitmq-server/deps/rabbit_common/mk/rabbitmq-components.mk rename to deps/rabbitmq_amqp1_0/rabbitmq-components.mk index 1e5d000..05986d8 100644 --- a/rabbitmq-server/deps/rabbit_common/mk/rabbitmq-components.mk +++ b/deps/rabbitmq_amqp1_0/rabbitmq-components.mk @@ -5,27 +5,6 @@ ifeq ($(.DEFAULT_GOAL),) .DEFAULT_GOAL = all endif -# PROJECT_VERSION defaults to: -# 1. the version exported by rabbitmq-server-release; -# 2. the version stored in `git-revisions.txt`, if it exists; -# 3. a version based on git-describe(1), if it is a Git clone; -# 4. 0.0.0 - -PROJECT_VERSION := $(RABBITMQ_VERSION) - -ifeq ($(PROJECT_VERSION),) -PROJECT_VERSION := $(shell \ -if test -f git-revisions.txt; then \ - head -n1 git-revisions.txt | \ - awk '{print $$$(words $(PROJECT_DESCRIPTION) version);}'; \ -else \ - (git describe --dirty --abbrev=7 --tags --always --first-parent \ - 2>/dev/null || echo rabbitmq_v0_0_0) | \ - sed -e 's/^rabbitmq_v//' -e 's/^v//' -e 's/_/./g' -e 's/-/+/' \ - -e 's/-/./g'; \ -fi) -endif - # -------------------------------------------------------------------- # RabbitMQ components. # -------------------------------------------------------------------- @@ -42,17 +21,13 @@ dep_rabbit = git_rmq rabbitmq-server $(current_rmq_re dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_auth_backend_cache = git_rmq rabbitmq-auth-backend-cache $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_aws = git_rmq rabbitmq-aws $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_cli = git_rmq rabbitmq-cli $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_ct_client_helpers = git_rmq rabbitmq-ct-client-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master @@ -61,7 +36,6 @@ dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rm dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_jms_cts = git_rmq rabbitmq-jms-cts $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master @@ -73,11 +47,6 @@ dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(cur dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_aws = git_rmq rabbitmq-peer-discovery-aws $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_common = git_rmq rabbitmq-peer-discovery-common $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_consul = git_rmq rabbitmq-peer-discovery-consul $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_etcd = git_rmq rabbitmq-peer-discovery-etcd $(current_rmq_ref) $(base_rmq_ref) master -dep_rabbitmq_peer_discovery_k8s = git_rmq rabbitmq-peer-discovery-k8s $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master @@ -97,41 +66,30 @@ dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(cu dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master -# Third-party dependencies version pinning. -# -# We do that in this file, which is copied in all projects, to ensure -# all projects use the same versions. It avoids conflicts and makes it -# possible to work with rabbitmq-public-umbrella. - -dep_cowboy_commit = 1.0.4 -dep_mochiweb = git git://github.com/basho/mochiweb.git v2.9.0p2 -# Last commit of PropEr supporting Erlang R16B03. -dep_proper_commit = 735d972758d8bd85b12483626fe1b66450d6a6fe -dep_ranch_commit = 1.3.2 -# Last commit of sockjs support Erlang R16B03 and 17.x. -dep_sockjs = git https://github.com/rabbitmq/sockjs-erlang.git 5af2b588c812c318b19bc105b577a759c71c3e0a -dep_webmachine_commit = 1.10.8p2 +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 RABBITMQ_COMPONENTS = amqp_client \ rabbit \ rabbit_common \ rabbitmq_amqp1_0 \ rabbitmq_auth_backend_amqp \ - rabbitmq_auth_backend_cache \ rabbitmq_auth_backend_http \ rabbitmq_auth_backend_ldap \ rabbitmq_auth_mechanism_ssl \ - rabbitmq_aws \ rabbitmq_boot_steps_visualiser \ rabbitmq_clusterer \ - rabbitmq_cli \ rabbitmq_codegen \ rabbitmq_consistent_hash_exchange \ - rabbitmq_ct_client_helpers \ rabbitmq_ct_helpers \ rabbitmq_delayed_message_exchange \ rabbitmq_dotnet_client \ @@ -140,7 +98,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_federation_management \ rabbitmq_java_client \ rabbitmq_jms_client \ - rabbitmq_jms_cts \ rabbitmq_jms_topic_exchange \ rabbitmq_lvc \ rabbitmq_management \ @@ -152,11 +109,6 @@ RABBITMQ_COMPONENTS = amqp_client \ rabbitmq_metronome \ rabbitmq_mqtt \ rabbitmq_objc_client \ - rabbitmq_peer_discovery_aws \ - rabbitmq_peer_discovery_common \ - rabbitmq_peer_discovery_consul \ - rabbitmq_peer_discovery_etcd \ - rabbitmq_peer_discovery_k8s \ rabbitmq_recent_history_exchange \ rabbitmq_routing_node_stamp \ rabbitmq_rtopic_exchange \ diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/messaging.xml b/deps/rabbitmq_amqp1_0/spec/messaging.xml similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/messaging.xml rename to deps/rabbitmq_amqp1_0/spec/messaging.xml diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/security.xml b/deps/rabbitmq_amqp1_0/spec/security.xml similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/security.xml rename to deps/rabbitmq_amqp1_0/spec/security.xml diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/transactions.xml b/deps/rabbitmq_amqp1_0/spec/transactions.xml similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/transactions.xml rename to deps/rabbitmq_amqp1_0/spec/transactions.xml diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/transport.xml b/deps/rabbitmq_amqp1_0/spec/transport.xml similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/transport.xml rename to deps/rabbitmq_amqp1_0/spec/transport.xml diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/types.xml b/deps/rabbitmq_amqp1_0/spec/types.xml similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-1.0/types.xml rename to deps/rabbitmq_amqp1_0/spec/types.xml diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl index a941028..cff8495 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_generator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_binary_generator). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl index 44c75f0..5a9f49f 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_binary_parser.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_binary_parser). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl index 1eb247b..2e5a4b2 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_channel.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_channel). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl similarity index 91% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl index c2e404c..0ff6b43 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_framing.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_framing). @@ -52,9 +52,12 @@ fill_from_map(Record, Fields) -> {Record, 2}, keys(Record)), Res. -fill_from(F = #'v1_0.data'{}, Field) -> - F#'v1_0.data'{content = Field}; -fill_from(F = #'v1_0.amqp_value'{}, Field) -> +%% TODO should this be part of a more general handler for AMQP values etc? +fill_from_binary(F = #'v1_0.data'{}, Field) -> + F#'v1_0.data'{content = Field}. + +%% TODO so should this? +fill_from_amqp(F = #'v1_0.amqp_value'{}, Field) -> F#'v1_0.amqp_value'{content = Field}. keys(Record) -> @@ -91,14 +94,9 @@ decode({described, Descriptor, {map, Fields}}) -> fill_from_map(Else, Fields) end; decode({described, Descriptor, {binary, Field}}) -> - case rabbit_amqp1_0_framing0:record_for(Descriptor) of - #'v1_0.amqp_value'{} -> - #'v1_0.amqp_value'{content = {binary, Field}}; - #'v1_0.data'{} -> - #'v1_0.data'{content = Field} - end; + fill_from_binary(rabbit_amqp1_0_framing0:record_for(Descriptor), Field); decode({described, Descriptor, Field}) -> - fill_from(rabbit_amqp1_0_framing0:record_for(Descriptor), Field); + fill_from_amqp(rabbit_amqp1_0_framing0:record_for(Descriptor), Field); decode(null) -> undefined; decode(Other) -> diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl index 65636af..46748b1 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_incoming_link.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_incoming_link). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl index 63e7463..85e003d 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_link_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_link_util). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl index 37a4ca3..19d5fc0 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_message.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_message). @@ -172,16 +172,16 @@ unwrap({_Type, Thing}) -> Thing. to_expiration(undefined) -> undefined; -to_expiration({uint, Num}) -> +to_expiration({timestamp, Num}) -> list_to_binary(integer_to_list(Num)). from_expiration(undefined) -> undefined; -from_expiration(PBasic) -> - case rabbit_basic:parse_expiration(PBasic) of - {ok, undefined} -> undefined; - {ok, N} -> {uint, N}; - _ -> undefined +from_expiration(MaybeIntegerBin) -> + case catch list_to_integer(binary_to_list(MaybeIntegerBin)) of + {'EXIT', {badarg, _}} -> + undefined; + Integer -> {timestamp, Integer} end. set_header(Header, Value, undefined) -> @@ -206,7 +206,7 @@ annotated_message(RKey, #'basic.deliver'{redelivered = Redelivered}, _ -> false end, priority = wrap(ubyte, Props#'P_basic'.priority), - ttl = from_expiration(Props), + ttl = from_expiration(Props#'P_basic'.expiration), first_acquirer = not Redelivered, delivery_count = undefined}, HeadersBin = rabbit_amqp1_0_framing:encode_bin(Header10), diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl index 5d03b84..f0366c8 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_outgoing_link.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_outgoing_link). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl index 0203268..dd46010 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_reader.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_reader). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl index 4909a0d..5a3ae02 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_session). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl index 91c3432..68cc49c 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_process.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_session_process). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl index f7f7684..ee09d76 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_session_sup). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl index 88965a7..4fff8b4 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_session_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_session_sup_sup). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl index 9cf217f..7c6786f 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_util). diff --git a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl rename to deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl index 71825d7..03b02fb 100644 --- a/rabbitmq-server/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl +++ b/deps/rabbitmq_amqp1_0/src/rabbit_amqp1_0_writer.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_amqp1_0_writer). diff --git a/deps/rabbitmq_amqp1_0/src/rabbitmq_amqp1_0.app.src b/deps/rabbitmq_amqp1_0/src/rabbitmq_amqp1_0.app.src new file mode 100644 index 0000000..da7914e --- /dev/null +++ b/deps/rabbitmq_amqp1_0/src/rabbitmq_amqp1_0.app.src @@ -0,0 +1,9 @@ +{application, rabbitmq_amqp1_0, + [{description, "AMQP 1.0 support for RabbitMQ"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {env, [{default_user, "guest"}, + {default_vhost, <<"/">>}, + {protocol_strict_mode, false}]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, amqp_client]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/CODE_OF_CONDUCT.md b/deps/rabbitmq_auth_backend_ldap/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/CODE_OF_CONDUCT.md rename to deps/rabbitmq_auth_backend_ldap/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/CONTRIBUTING.md b/deps/rabbitmq_auth_backend_ldap/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/CONTRIBUTING.md rename to deps/rabbitmq_auth_backend_ldap/CONTRIBUTING.md diff --git a/deps/rabbitmq_auth_backend_ldap/Makefile b/deps/rabbitmq_auth_backend_ldap/Makefile new file mode 100644 index 0000000..c33e998 --- /dev/null +++ b/deps/rabbitmq_auth_backend_ldap/Makefile @@ -0,0 +1,16 @@ +PROJECT = rabbitmq_auth_backend_ldap + +DEPS = rabbit_common rabbit +TEST_DEPS = ct_helper rabbitmq_ct_helpers amqp_client +dep_ct_helper = git https://github.com/extend/ct_helper.git master + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README-authorisation.md b/deps/rabbitmq_auth_backend_ldap/README-authorisation.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README-authorisation.md rename to deps/rabbitmq_auth_backend_ldap/README-authorisation.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README-tests.md b/deps/rabbitmq_auth_backend_ldap/README-tests.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README-tests.md rename to deps/rabbitmq_auth_backend_ldap/README-tests.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README.md b/deps/rabbitmq_auth_backend_ldap/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/README.md rename to deps/rabbitmq_auth_backend_ldap/README.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/Vagrantfile b/deps/rabbitmq_auth_backend_ldap/Vagrantfile similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/Vagrantfile rename to deps/rabbitmq_auth_backend_ldap/Vagrantfile diff --git a/deps/rabbitmq_auth_backend_ldap/erlang.mk b/deps/rabbitmq_auth_backend_ldap/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_auth_backend_ldap/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/global.ldif b/deps/rabbitmq_auth_backend_ldap/example/global.ldif similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/global.ldif rename to deps/rabbitmq_auth_backend_ldap/example/global.ldif diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/memberof_init.ldif b/deps/rabbitmq_auth_backend_ldap/example/memberof_init.ldif similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/memberof_init.ldif rename to deps/rabbitmq_auth_backend_ldap/example/memberof_init.ldif diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/refint_1.ldif b/deps/rabbitmq_auth_backend_ldap/example/refint_1.ldif similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/refint_1.ldif rename to deps/rabbitmq_auth_backend_ldap/example/refint_1.ldif diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/refint_2.ldif b/deps/rabbitmq_auth_backend_ldap/example/refint_2.ldif similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/refint_2.ldif rename to deps/rabbitmq_auth_backend_ldap/example/refint_2.ldif diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/seed.sh b/deps/rabbitmq_auth_backend_ldap/example/seed.sh similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/seed.sh rename to deps/rabbitmq_auth_backend_ldap/example/seed.sh diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/setup.sh b/deps/rabbitmq_auth_backend_ldap/example/setup.sh similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/example/setup.sh rename to deps/rabbitmq_auth_backend_ldap/example/setup.sh diff --git a/deps/rabbitmq_auth_backend_ldap/rabbitmq-components.mk b/deps/rabbitmq_auth_backend_ldap/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_auth_backend_ldap/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl similarity index 88% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl rename to deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl index 6e14c8c..7915caf 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl +++ b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap). @@ -27,11 +27,6 @@ -export([user_login_authentication/2, user_login_authorization/1, check_vhost_access/3, check_resource_access/3]). --export([get_connections/0]). - -%% for tests --export([purge_connections/0]). - -define(L(F, A), log("LDAP " ++ F, A)). -define(L1(F, A), log(" LDAP " ++ F, A)). -define(L2(F, A), log(" LDAP " ++ F, A)). @@ -43,15 +38,6 @@ %%-------------------------------------------------------------------- -get_connections() -> - worker_pool:submit(ldap_pool, fun() -> get(ldap_conns) end, reuse). - -purge_connections() -> - [ok = worker_pool:submit(ldap_pool, - fun() -> purge_conn(Anon, Servers, Opts) end, reuse) - || {{Anon, Servers, Opts}, _} <- dict:to_list(get_connections())], - ok. - user_login_authentication(Username, []) -> %% Without password, e.g. EXTERNAL ?L("CHECK: passwordless login for ~s", [Username]), @@ -217,42 +203,13 @@ evaluate0({equals, StringQuery1, StringQuery2}, Args, User, LDAP) -> evaluate(StringQuery1, Args, User, LDAP), evaluate(StringQuery2, Args, User, LDAP)); -evaluate0({match, {string, _} = StringQuery, {string, _} = REQuery}, Args, User, LDAP) -> +evaluate0({match, StringQuery, REQuery}, Args, User, LDAP) -> safe_eval(fun (String1, String2) -> do_match(String1, String2) end, evaluate(StringQuery, Args, User, LDAP), evaluate(REQuery, Args, User, LDAP)); -evaluate0({match, StringQuery, {string, _} = REQuery}, Args, User, LDAP) when is_list(StringQuery)-> - safe_eval(fun (String1, String2) -> - do_match(String1, String2) - end, - evaluate(StringQuery, Args, User, LDAP), - evaluate(REQuery, Args, User, LDAP)); - -evaluate0({match, {string, _} = StringQuery, REQuery}, Args, User, LDAP) when is_list(REQuery) -> - safe_eval(fun (String1, String2) -> - do_match(String1, String2) - end, - evaluate(StringQuery, Args, User, LDAP), - evaluate(REQuery, Args, User, LDAP)); - -evaluate0({match, StringQuery, REQuery}, Args, User, LDAP) when is_list(StringQuery), - is_list(REQuery) -> - safe_eval(fun (String1, String2) -> - do_match(String1, String2) - end, - evaluate(StringQuery, Args, User, LDAP), - evaluate(REQuery, Args, User, LDAP)); - -evaluate0({match, StringQuery, REQuery}, Args, User, LDAP) -> - safe_eval(fun (String1, String2) -> - do_match_bidirectionally(String1, String2) - end, - evaluate(StringQuery, Args, User, LDAP), - evaluate(REQuery, Args, User, LDAP)); - evaluate0(StringPattern, Args, User, LDAP) when is_list(StringPattern) -> evaluate0({string, StringPattern}, Args, User, LDAP); @@ -313,14 +270,6 @@ safe_eval(_F, _, {error, _}) -> false; safe_eval(F, V1, V2) -> F(V1, V2). do_match(S1, S2) -> - case re:run(S1, S2) of - {match, _} -> log_match(S1, S2, R = true), - R; - nomatch -> log_match(S1, S2, R = false), - R - end. - -do_match_bidirectionally(S1, S2) -> case re:run(S1, S2) of {match, _} -> log_match(S1, S2, R = true), R; @@ -388,9 +337,7 @@ with_ldap({error, _} = E, _Fun, _State) -> %% to avoid rebinding if the connection is already bound as the user %% of interest, so this could still be more efficient. with_ldap({ok, Creds}, Fun, Servers) -> - Opts0 = [{port, env(port)}, - {idle_timeout, env(idle_timeout)}, - {anon_auth, env(anon_auth)}], + Opts0 = [{port, env(port)}], Opts1 = case env(log) of network -> Pre = " LDAP network traffic: ", @@ -415,7 +362,6 @@ with_ldap({ok, Creds}, Fun, Servers) -> infinity -> Opts1; MS -> [{timeout, MS} | Opts1] end, - worker_pool:submit( ldap_pool, fun () -> @@ -466,42 +412,14 @@ get_or_create_conn(IsAnon, Servers, Opts) -> end, Key = {IsAnon, Servers, Opts}, case dict:find(Key, Conns) of - {ok, Conn} -> - Timeout = rabbit_misc:pget(idle_timeout, Opts, infinity), - %% Defer the timeout by re-setting it. - set_connection_timeout(Key, Timeout), - {ok, Conn}; + {ok, Conn} -> Conn; error -> - {Timeout, EldapOpts} = case lists:keytake(idle_timeout, 1, Opts) of - false -> {infinity, Opts}; - {value, {idle_timeout, T}, EOpts} -> {T, EOpts} - end, - case eldap_open(Servers, EldapOpts) of - {ok, Conn} -> - put(ldap_conns, dict:store(Key, Conn, Conns)), - set_connection_timeout(Key, Timeout), - {ok, Conn}; + case eldap_open(Servers, Opts) of + {ok, _} = Conn -> put(ldap_conns, dict:store(Key, Conn, Conns)), Conn; Error -> Error end end. -set_connection_timeout(_, infinity) -> - ok; -set_connection_timeout(Key, Timeout) when is_integer(Timeout) -> - worker_pool_worker:set_timeout(Key, Timeout, - fun() -> - Conns = case get(ldap_conns) of - undefined -> dict:new(); - Dict -> Dict - end, - case dict:find(Key, Conns) of - {ok, Conn} -> - eldap:close(Conn), - put(ldap_conns, dict:erase(Key, Conns)); - _ -> ok - end - end). - %% Get attribute(s) from eldap entry get_attributes(_AttrName, []) -> {error, not_found}; get_attributes(AttrName, [#eldap_entry{attributes = A}|Rem]) -> @@ -528,7 +446,7 @@ is_multi_attr_member(Str1, Str2) -> purge_conn(IsAnon, Servers, Opts) -> Conns = get(ldap_conns), Key = {IsAnon, Servers, Opts}, - {ok, Conn} = dict:find(Key, Conns), + {_, {_, Conn}} = dict:find(Key, Conns), rabbit_log:warning("LDAP Purging an already closed LDAP server connection~n"), % We cannot close the connection with eldap:close/1 because as of OTP-13327 % eldap will try to do_unbind first and will fail with a `{gen_tcp_error, closed}`. @@ -536,8 +454,7 @@ purge_conn(IsAnon, Servers, Opts) -> % kill its process. unlink(Conn), exit(Conn, closed), - put(ldap_conns, dict:erase(Key, Conns)), - ok. + put(ldap_conns, dict:erase(Key, Conns)). eldap_open(Servers, Opts) -> case eldap:open(Servers, ssl_conf() ++ Opts) of diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl similarity index 91% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl rename to deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl index f239f61..e96a377 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl +++ b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_app). @@ -25,7 +25,7 @@ -rabbit_boot_step({ldap_pool, [{description, "LDAP pool"}, - {mfa, {?MODULE, create_ldap_pool, []}}, + {mfa, {?MODULE, create_ldap_pool, []}}, {requires, kernel_ready}]}). create_ldap_pool() -> @@ -43,9 +43,7 @@ start(_Type, _StartArgs) -> {ok, SSL} = application:get_env(rabbitmq_auth_backend_ldap, use_ssl), {ok, TLS} = application:get_env(rabbitmq_auth_backend_ldap, use_starttls), case SSL orelse TLS of - true -> - rabbit_networking:ensure_ssl(), - ok; + true -> rabbit_networking:ensure_ssl(); false -> ok end, supervisor:start_link({local, ?MODULE}, ?MODULE, []). diff --git a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl rename to deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl index 3ee9c81..86216ac 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl +++ b/deps/rabbitmq_auth_backend_ldap/src/rabbit_auth_backend_ldap_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_backend_ldap_util). diff --git a/deps/rabbitmq_auth_backend_ldap/src/rabbitmq_auth_backend_ldap.app.src b/deps/rabbitmq_auth_backend_ldap/src/rabbitmq_auth_backend_ldap.app.src new file mode 100644 index 0000000..0277d84 --- /dev/null +++ b/deps/rabbitmq_auth_backend_ldap/src/rabbitmq_auth_backend_ldap.app.src @@ -0,0 +1,25 @@ +%% -*- erlang -*- +{application, rabbitmq_auth_backend_ldap, + [{description, "RabbitMQ LDAP Authentication Backend"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_auth_backend_ldap_app, []}}, + {env, [ {servers, undefined}, + {user_dn_pattern, "${username}"}, + {dn_lookup_attribute, none}, + {dn_lookup_base, none}, + {group_lookup_base, none}, + {dn_lookup_bind, as_user}, + {other_bind, as_user}, + {vhost_access_query, {constant, true}}, + {resource_access_query, {constant, true}}, + {tag_queries, [{administrator, {constant, false}}]}, + {use_ssl, false}, + {use_starttls, false}, + {ssl_options, []}, + {port, 3890}, + {timeout, infinity}, + {log, false}, + {pool_size, 64} ] }, + {applications, [kernel, stdlib, eldap, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/CODE_OF_CONDUCT.md b/deps/rabbitmq_auth_mechanism_ssl/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/CODE_OF_CONDUCT.md rename to deps/rabbitmq_auth_mechanism_ssl/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_codegen/CONTRIBUTING.md b/deps/rabbitmq_auth_mechanism_ssl/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/CONTRIBUTING.md rename to deps/rabbitmq_auth_mechanism_ssl/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/Makefile b/deps/rabbitmq_auth_mechanism_ssl/Makefile similarity index 59% rename from rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/Makefile rename to deps/rabbitmq_auth_mechanism_ssl/Makefile index 10f40c7..c10616c 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/Makefile +++ b/deps/rabbitmq_auth_mechanism_ssl/Makefile @@ -1,16 +1,7 @@ PROJECT = rabbitmq_auth_mechanism_ssl -PROJECT_DESCRIPTION = RabbitMQ SSL authentication (SASL EXTERNAL) -PROJECT_MOD = rabbit_auth_mechanism_ssl_app - -define PROJECT_ENV -[ - {name_from, distinguished_name} - ] -endef DEPS = rabbit_common rabbit -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/deps/rabbitmq_auth_mechanism_ssl/README.md b/deps/rabbitmq_auth_mechanism_ssl/README.md new file mode 100644 index 0000000..8d659ec --- /dev/null +++ b/deps/rabbitmq_auth_mechanism_ssl/README.md @@ -0,0 +1,62 @@ +# x509 (TLS/SSL) certificate Authentication Mechanism for RabbitMQ + +Authenticates the user, obtaining the username from the client's +SSL certificate. The user's password is not checked. + +In order to use this mechanism the client must connect over SSL, and +present a client certificate. + +The mechanism must also be enabled in RabbitMQ's configuration file - +see [TLS Authentication guide](http://www.rabbitmq.com/authentication.html) for more details, or +in short, ensure that the 'rabbit' section of your configuration +contains: + +``` erlang +{auth_mechanisms, ['PLAIN', 'AMQPLAIN', 'EXTERNAL']} +``` + +to allow this mechanism in addition to the defaults, or: + +``` erlang +{auth_mechanisms, ['EXTERNAL']} +``` + +to allow only this mechanism. + +For safety the server must be configured with the SSL option 'verify' +set to 'verify_peer', to ensure that if an SSL client presents a +certificate, it gets verified. + +By default this will set the username to an RFC4514-ish string form of +the certificate's subject's Distinguished Name, similar to that +produced by OpenSSL's "-nameopt RFC2253" option. + +You can obtain this string form from a certificate with a command like: + +``` +openssl x509 -in path/to/cert.pem -nameopt RFC2253 -subject -noout +``` + +or from an existing amqps connection with commands like: + +``` +rabbitmqctl list_connections peer_cert_subject +``` + +To use the Common Name instead, ensure that the 'rabbit' section of +your configuration contains: + +``` +{ssl_cert_login_from, common_name} +``` + +Note that the authenticated user will then be looked up in the +configured authentication / authorisation backend(s) - this will be +the mnesia-based user database by default, but could include other +backends if so configured. + +## Copyright & License + +(c) Pivotal Software Inc., 2007 — 2015. + +Released under the same license as RabbitMQ. diff --git a/deps/rabbitmq_auth_mechanism_ssl/erlang.mk b/deps/rabbitmq_auth_mechanism_ssl/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_auth_mechanism_ssl/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/deps/rabbitmq_auth_mechanism_ssl/rabbitmq-components.mk b/deps/rabbitmq_auth_mechanism_ssl/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_auth_mechanism_ssl/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl b/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl rename to deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl index f370b21..b7dac3f 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl +++ b/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% diff --git a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl b/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl rename to deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl index 9a33459..159cccc 100644 --- a/rabbitmq-server/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl +++ b/deps/rabbitmq_auth_mechanism_ssl/src/rabbit_auth_mechanism_ssl_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_auth_mechanism_ssl_app). diff --git a/deps/rabbitmq_auth_mechanism_ssl/src/rabbitmq_auth_mechanism_ssl.app.src b/deps/rabbitmq_auth_mechanism_ssl/src/rabbitmq_auth_mechanism_ssl.app.src new file mode 100644 index 0000000..d40920c --- /dev/null +++ b/deps/rabbitmq_auth_mechanism_ssl/src/rabbitmq_auth_mechanism_ssl.app.src @@ -0,0 +1,9 @@ +%% -*- erlang -*- +{application, rabbitmq_auth_mechanism_ssl, + [{description, "RabbitMQ SSL authentication (SASL EXTERNAL)"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_auth_mechanism_ssl_app, []}}, + {env, [{name_from, distinguished_name}] }, + {applications, [kernel, stdlib, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_codegen/CODE_OF_CONDUCT.md b/deps/rabbitmq_codegen/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/CODE_OF_CONDUCT.md rename to deps/rabbitmq_codegen/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/CONTRIBUTING.md b/deps/rabbitmq_codegen/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/CONTRIBUTING.md rename to deps/rabbitmq_codegen/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_codegen/LICENSE b/deps/rabbitmq_codegen/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/LICENSE rename to deps/rabbitmq_codegen/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_codegen/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_codegen/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_codegen/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_codegen/Makefile b/deps/rabbitmq_codegen/Makefile similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/Makefile rename to deps/rabbitmq_codegen/Makefile diff --git a/rabbitmq-server/deps/rabbitmq_codegen/README.extensions.md b/deps/rabbitmq_codegen/README.extensions.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/README.extensions.md rename to deps/rabbitmq_codegen/README.extensions.md diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-rabbitmq-0.8.json b/deps/rabbitmq_codegen/amqp-rabbitmq-0.8.json similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-rabbitmq-0.8.json rename to deps/rabbitmq_codegen/amqp-rabbitmq-0.8.json diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp-rabbitmq-0.9.1.json b/deps/rabbitmq_codegen/amqp-rabbitmq-0.9.1.json similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp-rabbitmq-0.9.1.json rename to deps/rabbitmq_codegen/amqp-rabbitmq-0.9.1.json diff --git a/rabbitmq-server/deps/rabbitmq_codegen/amqp_codegen.py b/deps/rabbitmq_codegen/amqp_codegen.py similarity index 87% rename from rabbitmq-server/deps/rabbitmq_codegen/amqp_codegen.py rename to deps/rabbitmq_codegen/amqp_codegen.py index bf5db38..e4de0e0 100644 --- a/rabbitmq-server/deps/rabbitmq_codegen/amqp_codegen.py +++ b/deps/rabbitmq_codegen/amqp_codegen.py @@ -14,7 +14,7 @@ ## Copyright (c) 2007-2014 GoPivotal, Inc. All rights reserved. ## -from __future__ import nested_scopes, print_function +from __future__ import nested_scopes import errno import re import sys @@ -30,15 +30,15 @@ try: else: raise e except ImportError: - print(" You don't appear to have simplejson.py installed", file = sys.stderr) - print(" (an implementation of a JSON reader and writer in Python).", file = sys.stderr) - print(" You can install it:", file = sys.stderr) - print(" - by running 'apt-get install python-simplejson' on Debian-based systems,", file = sys.stderr) - print(" - by running 'yum install python-simplejson' on Fedora/Red Hat system,", file = sys.stderr) - print(" - by running 'port install py25-simplejson' on Macports on OS X", file = sys.stderr) - print(" (you may need to say 'make PYTHON=python2.5', as well),", file = sys.stderr) - print(" - from sources from 'http://pypi.python.org/pypi/simplejson'", file = sys.stderr) - print(" - simplejson is a standard json library in the Python core since 2.6", file = sys.stderr) + print >> sys.stderr , " You don't appear to have simplejson.py installed" + print >> sys.stderr , " (an implementation of a JSON reader and writer in Python)." + print >> sys.stderr , " You can install it:" + print >> sys.stderr , " - by running 'apt-get install python-simplejson' on Debian-based systems," + print >> sys.stderr , " - by running 'yum install python-simplejson' on Fedora/Red Hat system," + print >> sys.stderr , " - by running 'port install py25-simplejson' on Macports on OS X" + print >> sys.stderr , " (you may need to say 'make PYTHON=python2.5', as well)," + print >> sys.stderr , " - from sources from 'http://pypi.python.org/pypi/simplejson'" + print >> sys.stderr , " - simplejson is a standard json library in the Python core since 2.6" sys.exit(1) def insert_base_types(d): @@ -140,7 +140,7 @@ class AmqpSpec: self.major = self.spec['major-version'] self.minor = self.spec['minor-version'] - self.revision = ('revision' in self.spec) and (self.spec['revision'] or 0) + self.revision = 'revision' in self.spec and self.spec['revision'] or 0 self.port = self.spec['port'] self.domains = {} @@ -236,6 +236,7 @@ class AmqpField(AmqpEntity): self.domain = self.element['type'] else: self.domain = self.element['domain'] + if 'default-value' in self.element: self.defaultvalue = self.element['default-value'] else: @@ -249,9 +250,9 @@ def do_main(header_fn, body_fn): def do_main_dict(funcDict): def usage(): - print("Usage:", file = sys.stderr) - print(" {0} ... ".format(sys.argv[0]), file = sys.stderr) - print(" where is one of: {0}".format(", ".join([k for k in funcDict.keys()])), file = sys.stderr) + print >> sys.stderr , "Usage:" + print >> sys.stderr , " %s ... " % (sys.argv[0]) + print >> sys.stderr , " where is one of %s" % ", ".join([k for k in funcDict.keys()]) def mkdir_p(path): try: diff --git a/rabbitmq-server/deps/rabbitmq_codegen/credit_extension.json b/deps/rabbitmq_codegen/credit_extension.json similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/credit_extension.json rename to deps/rabbitmq_codegen/credit_extension.json diff --git a/rabbitmq-server/deps/rabbitmq_codegen/demo_extension.json b/deps/rabbitmq_codegen/demo_extension.json similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/demo_extension.json rename to deps/rabbitmq_codegen/demo_extension.json diff --git a/rabbitmq-server/deps/rabbitmq_codegen/license_info b/deps/rabbitmq_codegen/license_info similarity index 100% rename from rabbitmq-server/deps/rabbitmq_codegen/license_info rename to deps/rabbitmq_codegen/license_info diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/CODE_OF_CONDUCT.md b/deps/rabbitmq_consistent_hash_exchange/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/CODE_OF_CONDUCT.md rename to deps/rabbitmq_consistent_hash_exchange/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/CONTRIBUTING.md b/deps/rabbitmq_consistent_hash_exchange/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_event_exchange/CONTRIBUTING.md rename to deps/rabbitmq_consistent_hash_exchange/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/LICENSE b/deps/rabbitmq_consistent_hash_exchange/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/LICENSE rename to deps/rabbitmq_consistent_hash_exchange/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_consistent_hash_exchange/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_consistent_hash_exchange/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/Makefile b/deps/rabbitmq_consistent_hash_exchange/Makefile similarity index 66% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/Makefile rename to deps/rabbitmq_consistent_hash_exchange/Makefile index a6f8b40..b9c1f08 100644 --- a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/Makefile +++ b/deps/rabbitmq_consistent_hash_exchange/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_consistent_hash_exchange -PROJECT_DESCRIPTION = Consistent Hash Exchange Type DEPS = rabbit_common rabbit -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client +TEST_DEPS = rabbitmq_ct_helpers amqp_client -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/README.md b/deps/rabbitmq_consistent_hash_exchange/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/README.md rename to deps/rabbitmq_consistent_hash_exchange/README.md diff --git a/deps/rabbitmq_consistent_hash_exchange/erlang.mk b/deps/rabbitmq_consistent_hash_exchange/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_consistent_hash_exchange/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/deps/rabbitmq_consistent_hash_exchange/rabbitmq-components.mk b/deps/rabbitmq_consistent_hash_exchange/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_consistent_hash_exchange/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl b/deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl similarity index 95% rename from rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl rename to deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl index 23390fe..4113f01 100644 --- a/rabbitmq-server/deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl +++ b/deps/rabbitmq_consistent_hash_exchange/src/rabbit_exchange_type_consistent_hash.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Consistent Hash Exchange. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_consistent_hash). @@ -144,7 +144,7 @@ add_binding(transaction, _X, #bucket { source_number = {S, N}, destination = D, binding = B }, - write) || N <- find_numbers(S, D, BucketCount, [])], + write) || N <- find_numbers(S, BucketCount, [])], ok; _ -> ok @@ -176,12 +176,14 @@ init() -> mnesia:wait_for_tables([?TABLE], 30000), ok. -find_numbers(_Source, _Destination, 0, Acc) -> +find_numbers(_Source, 0, Acc) -> Acc; -find_numbers(Source, Destination, N, Acc) -> - Term = {Source, Destination, N}, - Number = erlang:phash2(Term, ?PHASH2_RANGE), - find_numbers(Source, Destination, N-1, [Number | Acc]). +find_numbers(Source, N, Acc) -> + Number = rand_compat:uniform(?PHASH2_RANGE) - 1, + case mnesia:read(?TABLE, {Source, Number}, write) of + [] -> find_numbers(Source, N-1, [Number | Acc]); + [_] -> find_numbers(Source, N, Acc) + end. hash(undefined, #basic_message { routing_keys = Routes }) -> Routes; diff --git a/deps/rabbitmq_consistent_hash_exchange/src/rabbitmq_consistent_hash_exchange.app.src b/deps/rabbitmq_consistent_hash_exchange/src/rabbitmq_consistent_hash_exchange.app.src new file mode 100644 index 0000000..4d9618c --- /dev/null +++ b/deps/rabbitmq_consistent_hash_exchange/src/rabbitmq_consistent_hash_exchange.app.src @@ -0,0 +1,7 @@ +{application, rabbitmq_consistent_hash_exchange, + [{description, "Consistent Hash Exchange Type"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {env, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/CODE_OF_CONDUCT.md b/deps/rabbitmq_event_exchange/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_event_exchange/CODE_OF_CONDUCT.md rename to deps/rabbitmq_event_exchange/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_federation/CONTRIBUTING.md b/deps/rabbitmq_event_exchange/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/CONTRIBUTING.md rename to deps/rabbitmq_event_exchange/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/LICENSE b/deps/rabbitmq_event_exchange/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_event_exchange/LICENSE rename to deps/rabbitmq_event_exchange/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_event_exchange/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_event_exchange/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_event_exchange/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/Makefile b/deps/rabbitmq_event_exchange/Makefile similarity index 66% rename from rabbitmq-server/deps/rabbitmq_event_exchange/Makefile rename to deps/rabbitmq_event_exchange/Makefile index 9d7c9f7..ea0157f 100644 --- a/rabbitmq-server/deps/rabbitmq_event_exchange/Makefile +++ b/deps/rabbitmq_event_exchange/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_event_exchange -PROJECT_DESCRIPTION = Event Exchange Type DEPS = rabbit_common rabbit -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client +TEST_DEPS = rabbitmq_ct_helpers amqp_client -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/README.md b/deps/rabbitmq_event_exchange/README.md similarity index 70% rename from rabbitmq-server/deps/rabbitmq_event_exchange/README.md rename to deps/rabbitmq_event_exchange/README.md index 171b7aa..9878bdc 100644 --- a/rabbitmq-server/deps/rabbitmq_event_exchange/README.md +++ b/deps/rabbitmq_event_exchange/README.md @@ -25,17 +25,24 @@ The plugin requires no configuration, just activate it: rabbitmq-plugins enable rabbitmq_event_exchange -## Downloading & Installation +## Downloading -### With RabbitMQ 3.6.0 or Later +You can download a pre-built binary of this plugin from +the [RabbitMQ Community Plugins](http://www.rabbitmq.com/community-plugins.html) page. -Most recent RabbitMQ version ships with this plugin. -### With RabbitMQ 3.5.x +## Building -You can download a pre-built binary of this plugin from -the [RabbitMQ Community Plugins](http://www.rabbitmq.com/community-plugins.html) page. +Building is no different from [building other RabbitMQ plugins](http://www.rabbitmq.com/plugin-development.html). + +TL;DR: + git clone https://github.com.com/rabbitmq/rabbitmq-public-umbrella.git + cd rabbitmq-public-umbrella + make co + git clone https://github.com/rabbitmq/rabbitmq-event-exchange.git + cd rabbitmq-event-exchange + make -j ## Event format @@ -51,70 +58,65 @@ So far RabbitMQ and related plugins emit events with the following routing keys: Queue, Exchange and Binding events: - * `queue.deleted` - * `queue.created` - * `exchange.created` - * `exchange.deleted` - * `binding.created` - * `binding.deleted` +- `queue.deleted` +- `queue.created` +- `exchange.created` +- `exchange.deleted` +- `binding.created` +- `binding.deleted` Connection and Channel events: - * `connection.created` - * `connection.closed` - * `channel.created` - * `channel.closed` +- `connection.created` +- `connection.closed` +- `channel.created` +- `channel.closed` Consumer events: - * `consumer.created` - * `consumer.deleted` +- `consumer.created` +- `consumer.deleted` Policy and Parameter events: - * `policy.set` - * `policy.cleared` - * `parameter.set` - * `parameter.cleared` +- `policy.set` +- `policy.cleared` +- `parameter.set` +- `parameter.cleared` Virtual host events: - * `vhost.created` - * `vhost.deleted` +- `vhost.created` +- `vhost.deleted` User related events: - * `user.authentication.success` - * `user.authentication.failure` - * `user.created` - * `user.deleted` - * `user.password.changed` - * `user.password.cleared` - * `user.tags.set` +- `user.authentication.success` +- `user.authentication.failure` +- `user.created` +- `user.deleted` +- `user.password.changed` +- `user.password.cleared` +- `user.tags.set` Permission events: - * `permission.created` - * `permission.deleted` - -Alarm events: - - * `alarm.set` - * `alarm.cleared` +- `permission.created` +- `permission.deleted` ### Shovel Plugin Worker events: - * `shovel.worker.status` - * `shovel.worker.removed` +- `shovel.worker.status` +- `shovel.worker.removed` ### Federation Plugin Link events: - * `federation.link.status` - * `federation.link.removed` +- `federation.link.status` +- `federation.link.removed` ## Example @@ -128,23 +130,6 @@ e.g. with : rabbitmqctl eval 'rabbit_exchange:delete(rabbit_misc:r(<<"/">>, exchange, <<"amq.rabbitmq.event">>), false).' - -## Building from Source - -Building is no different from [building other RabbitMQ plugins](http://www.rabbitmq.com/plugin-development.html). - -TL;DR: - - git clone https://github.com.com/rabbitmq/rabbitmq-public-umbrella.git - cd rabbitmq-public-umbrella - make co - make up BRANCH=stable - cd deps - git clone https://github.com/rabbitmq/rabbitmq-event-exchange.git rabbitmq_event_exchange - cd rabbitmq_event_exchange - make dist - - ## License Released under the Mozilla Public License 1.1, diff --git a/deps/rabbitmq_event_exchange/erlang.mk b/deps/rabbitmq_event_exchange/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_event_exchange/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/examples/java/QueueEvents.java b/deps/rabbitmq_event_exchange/examples/java/QueueEvents.java similarity index 100% rename from rabbitmq-server/deps/rabbitmq_event_exchange/examples/java/QueueEvents.java rename to deps/rabbitmq_event_exchange/examples/java/QueueEvents.java diff --git a/deps/rabbitmq_event_exchange/rabbitmq-components.mk b/deps/rabbitmq_event_exchange/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_event_exchange/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl b/deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl rename to deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl index 56e9850..978b335 100644 --- a/rabbitmq-server/deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl +++ b/deps/rabbitmq_event_exchange/src/rabbit_exchange_type_event.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_event). diff --git a/deps/rabbitmq_event_exchange/src/rabbitmq_event_exchange.app.src b/deps/rabbitmq_event_exchange/src/rabbitmq_event_exchange.app.src new file mode 100644 index 0000000..5fdc6a4 --- /dev/null +++ b/deps/rabbitmq_event_exchange/src/rabbitmq_event_exchange.app.src @@ -0,0 +1,7 @@ +{application, rabbitmq_event_exchange, + [{description, "Event Exchange Type"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {env, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_federation/CODE_OF_CONDUCT.md b/deps/rabbitmq_federation/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/CODE_OF_CONDUCT.md rename to deps/rabbitmq_federation/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/CONTRIBUTING.md b/deps/rabbitmq_federation/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/CONTRIBUTING.md rename to deps/rabbitmq_federation/CONTRIBUTING.md diff --git a/deps/rabbitmq_federation/Makefile b/deps/rabbitmq_federation/Makefile new file mode 100644 index 0000000..0da1e80 --- /dev/null +++ b/deps/rabbitmq_federation/Makefile @@ -0,0 +1,15 @@ +PROJECT = rabbitmq_federation + +DEPS = rabbit_common rabbit amqp_client +TEST_DEPS = rabbitmq_ct_helpers + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_federation/README-hacking b/deps/rabbitmq_federation/README-hacking similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/README-hacking rename to deps/rabbitmq_federation/README-hacking diff --git a/rabbitmq-server/deps/rabbitmq_federation/README.md b/deps/rabbitmq_federation/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/README.md rename to deps/rabbitmq_federation/README.md diff --git a/deps/rabbitmq_federation/erlang.mk b/deps/rabbitmq_federation/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_federation/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_federation/etc/rabbit-test.sh b/deps/rabbitmq_federation/etc/rabbit-test.sh similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/etc/rabbit-test.sh rename to deps/rabbitmq_federation/etc/rabbit-test.sh diff --git a/rabbitmq-server/deps/rabbitmq_federation/etc/setup-rabbit-test.sh b/deps/rabbitmq_federation/etc/setup-rabbit-test.sh similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/etc/setup-rabbit-test.sh rename to deps/rabbitmq_federation/etc/setup-rabbit-test.sh diff --git a/rabbitmq-server/deps/rabbitmq_federation/include/rabbit_federation.hrl b/deps/rabbitmq_federation/include/rabbit_federation.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation/include/rabbit_federation.hrl rename to deps/rabbitmq_federation/include/rabbit_federation.hrl diff --git a/deps/rabbitmq_federation/rabbitmq-components.mk b/deps/rabbitmq_federation/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_federation/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_app.erl b/deps/rabbitmq_federation/src/rabbit_federation_app.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_app.erl rename to deps/rabbitmq_federation/src/rabbit_federation_app.erl index a441d9c..28e0aae 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_app.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_app). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_db.erl b/deps/rabbitmq_federation/src/rabbit_federation_db.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_db.erl rename to deps/rabbitmq_federation/src/rabbit_federation_db.erl index ee4818a..82e06a9 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_db.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_db.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_db). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_event.erl b/deps/rabbitmq_federation/src/rabbit_federation_event.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_event.erl rename to deps/rabbitmq_federation/src/rabbit_federation_event.erl index 423ce4c..6e92816 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_event.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_event.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_event). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange.erl b/deps/rabbitmq_federation/src/rabbit_federation_exchange.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange.erl rename to deps/rabbitmq_federation/src/rabbit_federation_exchange.erl index c661755..773e204 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_exchange.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% TODO rename this diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl b/deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl similarity index 86% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl rename to deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl index 7737ebf..14e310f 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_exchange_link.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_exchange_link). @@ -46,9 +46,7 @@ downstream_connection, downstream_channel, downstream_exchange, - unacked, - internal_exchange_timer, - internal_exchange_interval}). + unacked}). %%---------------------------------------------------------------------------- @@ -82,7 +80,6 @@ init({Upstream, XName}) -> gen_server2:cast(self(), maybe_go), {ok, {not_started, {Upstream, UParams, XName}}}; {error, not_found} -> - rabbit_federation_link_util:log_warning(XName, "not found, stopping link~n", []), {stop, gone} end. @@ -109,17 +106,9 @@ handle_cast(go, State) -> handle_cast({enqueue, _, _}, State = {not_started, _}) -> {noreply, State}; -handle_cast({enqueue, Serial, Cmd}, - State = #state{waiting_cmds = Waiting, - downstream_exchange = XName}) -> +handle_cast({enqueue, Serial, Cmd}, State = #state{waiting_cmds = Waiting}) -> Waiting1 = gb_trees:insert(Serial, Cmd, Waiting), - try - {noreply, play_back_commands(State#state{waiting_cmds = Waiting1})} - catch exit:{{shutdown, {server_initiated_close, 404, Text}}, _} -> - rabbit_federation_link_util:log_warning( - XName, "detected upstream changes, restarting link: ~p~n", [Text]), - {stop, {shutdown, restart}, State} - end; + {noreply, play_back_commands(State#state{waiting_cmds = Waiting1})}; handle_cast(Msg, State) -> {stop, {unexpected_cast, Msg}, State}. @@ -177,16 +166,6 @@ handle_info({'DOWN', _Ref, process, Pid, Reason}, rabbit_federation_link_util:handle_down( Pid, Reason, Ch, DCh, {Upstream, UParams, XName}, State); -handle_info(check_internal_exchange, State = #state{internal_exchange = IntXNameBin, - internal_exchange_interval = Int}) -> - case check_internal_exchange(IntXNameBin, State) of - upstream_not_found -> - {stop, {shutdown, restart}, State}; - _ -> - TRef = erlang:send_after(Int, self(), check_internal_exchange), - {noreply, State#state{internal_exchange_timer = TRef}} - end; - handle_info(Msg, State) -> {stop, {unexpected_info, Msg}, State}. @@ -197,9 +176,7 @@ terminate(Reason, #state{downstream_connection = DConn, connection = Conn, upstream = Upstream, upstream_params = UParams, - downstream_exchange = XName, - internal_exchange_timer = TRef}) -> - timer:cancel(TRef), + downstream_exchange = XName}) -> rabbit_federation_link_util:ensure_connection_closed(DConn), rabbit_federation_link_util:ensure_connection_closed(Conn), rabbit_federation_link_util:log_terminate(Reason, Upstream, UParams, XName), @@ -368,7 +345,8 @@ update_binding(Args, #state{downstream_exchange = X, Hops = case rabbit_misc:table_lookup(Args, ?BINDING_HEADER) of undefined -> MaxHops; {array, All} -> [{table, Prev} | _] = All, - PrevHops = get_hops(Prev), + {short, PrevHops} = + rabbit_misc:table_lookup(Prev, <<"hops">>), case rabbit_federation_util:already_seen( UName, All) of true -> 0; @@ -389,8 +367,6 @@ update_binding(Args, #state{downstream_exchange = X, rabbit_basic:prepend_table_header(?BINDING_HEADER, Info, Args) end. - - key(#binding{key = Key, args = Args}) -> {Key, Args}. go(S0 = {not_started, {Upstream, UParams, DownXName}}) -> @@ -418,8 +394,6 @@ go(S0 = {not_started, {Upstream, UParams, DownXName}}) -> %% serial we will process. Since it compares larger than %% any number we never process any commands. And we will %% soon get told to stop anyway. - {ok, Interval} = application:get_env(rabbitmq_federation, - internal_exchange_check_interval), State = ensure_upstream_bindings( consume_from_upstream_queue( #state{upstream = Upstream, @@ -431,11 +405,9 @@ go(S0 = {not_started, {Upstream, UParams, DownXName}}) -> downstream_connection = DConn, downstream_channel = DCh, downstream_exchange = DownXName, - unacked = Unacked, - internal_exchange_interval = Interval}), + unacked = Unacked}), Bindings), - TRef = erlang:send_after(Interval, self(), check_internal_exchange), - {noreply, State#state{internal_exchange_timer = TRef}} + {noreply, State} end, Upstream, UParams, DownXName, S0). consume_from_upstream_queue( @@ -541,35 +513,6 @@ ensure_internal_exchange(IntXNameBin, amqp_channel:call(Ch, Fan) end). -check_internal_exchange(IntXNameBin, - #state{upstream = #upstream{max_hops = MaxHops}, - upstream_params = UParams, - downstream_exchange = XName}) -> - #upstream_params{params = Params} = UParams, - Base = #'exchange.declare'{exchange = IntXNameBin, - passive = true, - durable = true, - internal = true, - auto_delete = true}, - Purpose = [{<<"x-internal-purpose">>, longstr, <<"federation">>}], - XFUArgs = [{?MAX_HOPS_ARG, long, MaxHops}, - {?NODE_NAME_ARG, longstr, rabbit_nodes:cluster_name()} - | Purpose], - XFU = Base#'exchange.declare'{type = <<"x-federation-upstream">>, - arguments = XFUArgs}, - rabbit_federation_link_util:disposable_connection_call( - Params, XFU, fun(404, Text) -> - rabbit_federation_link_util:log_warning( - XName, "detected internal upstream exchange changes," - " restarting link: ~p~n", [Text]), - upstream_not_found; - (Code, Text) -> - rabbit_federation_link_util:log_warning( - XName, "internal upstream exchange check failed: ~p ~p~n", - [Code, Text]), - error - end). - upstream_queue_name(XNameBin, VHost, #resource{name = DownXNameBin, virtual_host = DownVHost}) -> Node = rabbit_nodes:cluster_name(), @@ -599,16 +542,3 @@ update_headers(#upstream_params{table = Table}, UName, Redelivered, Headers) -> header_for_name(unknown) -> []; header_for_name(Name) -> [{<<"cluster-name">>, longstr, Name}]. - -get_hops(Table) -> - case rabbit_misc:table_lookup(Table, <<"hops">>) of - %% see rabbit_binary_generator - {short, N} -> N; - {long, N} -> N; - {byte, N} -> N; - {signedint, N} -> N; - {unsignedbyte, N} -> N; - {unsignedshort, N} -> N; - {unsignedint, N} -> N; - {_, N} when is_integer(N) andalso N >= 0 -> N - end. diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl b/deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl similarity index 95% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl rename to deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl index efcb8ea..ccb2719 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_exchange_link_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_exchange_link_sup_sup). @@ -59,7 +59,7 @@ stop_child(X) -> %%---------------------------------------------------------------------------- init([]) -> - {ok, {{one_for_one, 1200, 60}, []}}. + {ok, {{one_for_one, 3, 10}, []}}. %% See comment in rabbit_federation_queue_link_sup_sup:id/1 id(X = #exchange{policy = Policy}) -> X1 = rabbit_exchange:immutable(X), diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl b/deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl rename to deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl index 30d4ed6..402fe30 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_link_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_link_sup). @@ -23,7 +23,7 @@ %% Supervises the upstream links for an exchange or queue. --export([start_link/1, adjust/3, restart/2]). +-export([start_link/1, adjust/3]). -export([init/1]). start_link(XorQ) -> @@ -70,11 +70,6 @@ adjust(Sup, Q = #amqqueue{}, {upstream_set, _}) -> adjust(Sup, XorQ, {clear_upstream_set, _}) -> adjust(Sup, XorQ, everything). -restart(Sup, Upstream) -> - ok = supervisor2:terminate_child(Sup, Upstream), - {ok, _Pid} = supervisor2:restart_child(Sup, Upstream), - ok. - start(Sup, Upstream, XorQ) -> {ok, _Pid} = supervisor2:start_child(Sup, spec(Upstream, XorQ)), ok. diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_util.erl b/deps/rabbitmq_federation/src/rabbit_federation_link_util.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_util.erl rename to deps/rabbitmq_federation/src/rabbit_federation_link_util.erl index d99281b..91730a0 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_link_util.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_link_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_link_util). @@ -23,7 +23,7 @@ -export([start_conn_ch/5, disposable_channel_call/2, disposable_channel_call/3, disposable_connection_call/3, ensure_connection_closed/1, log_terminate/4, unacked_new/0, ack/3, nack/3, forward/9, - handle_down/6, get_connection_name/2, log_warning/3]). + handle_down/6, get_connection_name/2]). %% temp -export([connection_error/6]). @@ -300,8 +300,6 @@ disposable_connection_call(Params, Method, ErrFun) -> amqp_channel:call(Ch, Method) catch exit:{{shutdown, {connection_closing, {server_initiated_close, Code, Txt}}}, _} -> - ErrFun(Code, Txt); - exit:{{shutdown, {server_initiated_close, Code, Txt}}, _} -> ErrFun(Code, Txt) after ensure_connection_closed(Conn) diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_parameters.erl b/deps/rabbitmq_federation/src/rabbit_federation_parameters.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_parameters.erl rename to deps/rabbitmq_federation/src/rabbit_federation_parameters.erl index 6e1a55c..30549f1 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_parameters.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_parameters.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_parameters). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue.erl b/deps/rabbitmq_federation/src/rabbit_federation_queue.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue.erl rename to deps/rabbitmq_federation/src/rabbit_federation_queue.erl index c7e1305..ec9ec8d 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_queue.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_queue). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl b/deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl rename to deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl index 79345f1..80785ee 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_queue_link.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_queue_link). @@ -77,7 +77,6 @@ init({Upstream, Queue = #amqqueue{name = QName}}) -> upstream = Upstream, upstream_params = UParams}}; {error, not_found} -> - rabbit_federation_link_util:log_warning(QName, "not found, stopping link~n", []), {stop, gone} end. diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl b/deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl rename to deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl index ce721eb..f5b6a34 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_queue_link_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_queue_link_sup_sup). @@ -57,7 +57,7 @@ stop_child(Q) -> %%---------------------------------------------------------------------------- init([]) -> - {ok, {{one_for_one, 1200, 60}, []}}. + {ok, {{one_for_one, 3, 10}, []}}. %% Clean out all mutable aspects of the queue except policy. We need %% to keep the entire queue around rather than just take its name diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_status.erl b/deps/rabbitmq_federation/src/rabbit_federation_status.erl similarity index 68% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_status.erl rename to deps/rabbitmq_federation/src/rabbit_federation_status.erl index 9f89bb8..af6c6c1 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_status.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_status.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_status). @@ -22,7 +22,7 @@ -export([start_link/0]). --export([report/4, remove_exchange_or_queue/1, remove/2, status/0, lookup/1]). +-export([report/4, remove_exchange_or_queue/1, remove/2, status/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -33,15 +33,14 @@ -define(ETS_NAME, ?MODULE). -record(state, {}). --record(entry, {key, uri, status, timestamp, id, supervisor, upstream}). +-record(entry, {key, uri, status, timestamp}). start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). report(Upstream, UParams, XorQName, Status) -> - [Supervisor | _] = get('$ancestors'), - gen_server:cast(?SERVER, {report, Supervisor, Upstream, UParams, XorQName, - Status, calendar:local_time()}). + gen_server:cast(?SERVER, {report, Upstream, UParams, XorQName, Status, + calendar:local_time()}). remove_exchange_or_queue(XorQName) -> gen_server:call(?SERVER, {remove_exchange_or_queue, XorQName}, infinity). @@ -52,9 +51,6 @@ remove(Upstream, XorQName) -> status() -> gen_server:call(?SERVER, status, infinity). -lookup(Id) -> - gen_server:call(?SERVER, {lookup, Id}, infinity). - init([]) -> ?ETS_NAME = ets:new(?ETS_NAME, [named_table, {keypos, #entry.key}, private]), @@ -72,33 +68,16 @@ handle_call({remove, Upstream, XorQName}, _From, State) -> end, {reply, ok, State}; -handle_call({lookup, Id}, _From, State) -> - Link = case ets:match_object(?ETS_NAME, match_id(Id)) of - [Entry] -> [{key, Entry#entry.key}, - {uri, Entry#entry.uri}, - {status, Entry#entry.status}, - {timestamp, Entry#entry.timestamp}, - {id, Entry#entry.id}, - {supervisor, Entry#entry.supervisor}, - {upstream, Entry#entry.upstream}]; - [] -> not_found - end, - {reply, Link, State}; - handle_call(status, _From, State) -> Entries = ets:tab2list(?ETS_NAME), {reply, [format(Entry) || Entry <- Entries], State}. -handle_cast({report, Supervisor, Upstream, #upstream_params{safe_uri = URI}, +handle_cast({report, Upstream, #upstream_params{safe_uri = URI}, XorQName, Status, Timestamp}, State) -> - Key = key(XorQName, Upstream), - Entry = #entry{key = Key, + Entry = #entry{key = key(XorQName, Upstream), status = Status, uri = URI, - timestamp = Timestamp, - supervisor = Supervisor, - upstream = Upstream, - id = unique_id(Key)}, + timestamp = Timestamp}, true = ets:insert(?ETS_NAME, Entry), rabbit_event:notify(federation_link_status, format(Entry)), {noreply, State}. @@ -121,8 +100,7 @@ format(#entry{status = Status, identity(#entry{key = {#resource{virtual_host = VHost, kind = Type, name = XorQNameBin}, - UpstreamName, UXorQNameBin}, - id = Id}) -> + UpstreamName, UXorQNameBin}}) -> case Type of exchange -> [{exchange, XorQNameBin}, {upstream_exchange, UXorQNameBin}]; @@ -130,14 +108,7 @@ identity(#entry{key = {#resource{virtual_host = VHost, {upstream_queue, UXorQNameBin}] end ++ [{type, Type}, {vhost, VHost}, - {upstream, UpstreamName}, - {id, Id}]. - -unique_id(Key) -> - << << case N >= 10 of - true -> N - 10 + $a; - false -> N + $0 end >> - || <> <= crypto:hash(sha, term_to_binary(Key)) >>. + {upstream, UpstreamName}]. split_status({running, ConnName}) -> [{status, running}, {local_connection, ConnName}]; @@ -165,16 +136,4 @@ match_entry(Key) -> #entry{key = Key, uri = '_', status = '_', - timestamp = '_', - id = '_', - supervisor = '_', - upstream = '_'}. - -match_id(Id) -> - #entry{key = '_', - uri = '_', - status = '_', - timestamp = '_', - id = Id, - supervisor = '_', - upstream = '_'}. + timestamp = '_'}. diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_sup.erl b/deps/rabbitmq_federation/src/rabbit_federation_sup.erl similarity index 86% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_sup.erl rename to deps/rabbitmq_federation/src/rabbit_federation_sup.erl index 1fd8726..f19e8c7 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_sup.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_sup). @@ -65,8 +65,4 @@ init([]) -> {rabbit_federation_queue_link_sup_sup, start_link, []}, transient, ?SUPERVISOR_WAIT, supervisor, [rabbit_federation_queue_link_sup_sup]}, - %% with default reconnect-delay of 5 second, this supports up to - %% 100 links constantly failing and being restarted a minute - %% (or 200 links if reconnect-delay is 10 seconds, 600 with 30 seconds, - %% etc: N * (60/reconnect-delay) <= 1200) - {ok, {{one_for_one, 1200, 60}, [Status, XLinkSupSup, QLinkSupSup]}}. + {ok, {{one_for_one, 3, 10}, [Status, XLinkSupSup, QLinkSupSup]}}. diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream.erl b/deps/rabbitmq_federation/src/rabbit_federation_upstream.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream.erl rename to deps/rabbitmq_federation/src/rabbit_federation_upstream.erl index 68405f2..3e00500 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_upstream.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_upstream). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl b/deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl rename to deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl index 400ceb9..61aaf6b 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_upstream_exchange.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_upstream_exchange). diff --git a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_util.erl b/deps/rabbitmq_federation/src/rabbit_federation_util.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_util.erl rename to deps/rabbitmq_federation/src/rabbit_federation_util.erl index dbe2c00..24bc138 100644 --- a/rabbitmq-server/deps/rabbitmq_federation/src/rabbit_federation_util.erl +++ b/deps/rabbitmq_federation/src/rabbit_federation_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_federation_util). diff --git a/deps/rabbitmq_federation/src/rabbitmq_federation.app.src b/deps/rabbitmq_federation/src/rabbitmq_federation.app.src new file mode 100644 index 0000000..6f8c2e8 --- /dev/null +++ b/deps/rabbitmq_federation/src/rabbitmq_federation.app.src @@ -0,0 +1,8 @@ +{application, rabbitmq_federation, + [{description, "RabbitMQ Federation"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_federation_app, []}}, + {env, [{pgroup_name_cluster_id, false}]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, amqp_client]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/CODE_OF_CONDUCT.md b/deps/rabbitmq_federation_management/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/CODE_OF_CONDUCT.md rename to deps/rabbitmq_federation_management/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/CONTRIBUTING.md b/deps/rabbitmq_federation_management/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/CONTRIBUTING.md rename to deps/rabbitmq_federation_management/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE b/deps/rabbitmq_federation_management/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE rename to deps/rabbitmq_federation_management/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-APACHE2-ExplorerCanvas b/deps/rabbitmq_federation_management/LICENSE-APACHE2-ExplorerCanvas similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-APACHE2-ExplorerCanvas rename to deps/rabbitmq_federation_management/LICENSE-APACHE2-ExplorerCanvas diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-BSD-base64js b/deps/rabbitmq_federation_management/LICENSE-BSD-base64js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-BSD-base64js rename to deps/rabbitmq_federation_management/LICENSE-BSD-base64js diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-EJS10 b/deps/rabbitmq_federation_management/LICENSE-MIT-EJS10 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-EJS10 rename to deps/rabbitmq_federation_management/LICENSE-MIT-EJS10 diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-Flot b/deps/rabbitmq_federation_management/LICENSE-MIT-Flot similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-Flot rename to deps/rabbitmq_federation_management/LICENSE-MIT-Flot diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-Sammy060 b/deps/rabbitmq_federation_management/LICENSE-MIT-Sammy060 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-Sammy060 rename to deps/rabbitmq_federation_management/LICENSE-MIT-Sammy060 diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-jQuery164 b/deps/rabbitmq_federation_management/LICENSE-MIT-jQuery164 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MIT-jQuery164 rename to deps/rabbitmq_federation_management/LICENSE-MIT-jQuery164 diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_federation_management/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_federation_management/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/Makefile b/deps/rabbitmq_federation_management/Makefile similarity index 57% rename from rabbitmq-server/deps/rabbitmq_federation_management/Makefile rename to deps/rabbitmq_federation_management/Makefile index 61660f4..7a9e150 100644 --- a/rabbitmq-server/deps/rabbitmq_federation_management/Makefile +++ b/deps/rabbitmq_federation_management/Makefile @@ -1,10 +1,7 @@ PROJECT = rabbitmq_federation_management -PROJECT_DESCRIPTION = RabbitMQ Federation Management -DEPS = rabbit_common rabbit rabbitmq_management rabbitmq_federation -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers +DEPS = rabbit_common rabbit rabbitmq_management webmachine -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/README.md b/deps/rabbitmq_federation_management/README.md similarity index 95% rename from rabbitmq-server/deps/rabbitmq_federation_management/README.md rename to deps/rabbitmq_federation_management/README.md index 7984921..d9e57b0 100644 --- a/rabbitmq-server/deps/rabbitmq_federation_management/README.md +++ b/deps/rabbitmq_federation_management/README.md @@ -33,6 +33,6 @@ and see under the `./plugins` directory. ## Copyright and License -(c) Pivotal Software Inc, 2007-2017. +(c) Pivotal Software Inc, 2007-2016. See `LICENSE` for license information. diff --git a/deps/rabbitmq_federation_management/erlang.mk b/deps/rabbitmq_federation_management/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_federation_management/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/federation.js b/deps/rabbitmq_federation_management/priv/www/js/federation.js similarity index 96% rename from rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/federation.js rename to deps/rabbitmq_federation_management/priv/www/js/federation.js index 2af226e..a5f74b4 100644 --- a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/federation.js +++ b/deps/rabbitmq_federation_management/priv/www/js/federation.js @@ -28,12 +28,7 @@ dispatcher_add(function(sammy) { if (sync_delete(this, '/parameters/:component/:vhost/:name')) go_to('#/federation-upstreams'); return false; - }); - sammy.del("#/restart-link", function(){ - if(sync_delete(this, '/federation-links/vhost/:vhost/:id/:node/restart')){ - update(); - } - }); + }); }); NAVIGATION['Admin'][0]['Federation Status'] = ['#/federation', "monitoring"]; diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstream.ejs b/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstream.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstream.ejs rename to deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstream.ejs diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstreams.ejs b/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstreams.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstreams.ejs rename to deps/rabbitmq_federation_management/priv/www/js/tmpl/federation-upstreams.ejs diff --git a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs b/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs similarity index 83% rename from rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs rename to deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs index b496daa..15910c9 100644 --- a/rabbitmq-server/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs +++ b/deps/rabbitmq_federation_management/priv/www/js/tmpl/federation.ejs @@ -18,8 +18,6 @@ State Inbound message rate Last changed - ID - Operations @@ -80,15 +78,6 @@ <% } %> <%= link.timestamp %> - <%= link.id %> - -
- - - - -
- <% } %> <% } %> diff --git a/deps/rabbitmq_federation_management/rabbitmq-components.mk b/deps/rabbitmq_federation_management/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_federation_management/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/deps/rabbitmq_federation_management/src/rabbit_federation_mgmt.erl b/deps/rabbitmq_federation_management/src/rabbit_federation_mgmt.erl new file mode 100644 index 0000000..b4dc5f5 --- /dev/null +++ b/deps/rabbitmq_federation_management/src/rabbit_federation_mgmt.erl @@ -0,0 +1,97 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_federation_mgmt). + +-behaviour(rabbit_mgmt_extension). + +-export([dispatcher/0, web_ui/0]). +-export([init/1, to_json/2, resource_exists/2, content_types_provided/2, + is_authorized/2]). + +-import(rabbit_misc, [pget/2]). + +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). + +dispatcher() -> [{["federation-links"], ?MODULE, []}, + {["federation-links", vhost], ?MODULE, []}]. +web_ui() -> [{javascript, <<"federation.js">>}]. + +%%-------------------------------------------------------------------- + +init(_Config) -> {ok, #context{}}. + +content_types_provided(ReqData, Context) -> + {[{"application/json", to_json}], ReqData, Context}. + +resource_exists(ReqData, Context) -> + {case rabbit_mgmt_util:vhost(ReqData) of + not_found -> false; + _ -> true + end, ReqData, Context}. + +to_json(ReqData, Context) -> + Chs = rabbit_mgmt_db:get_all_channels( + rabbit_mgmt_util:range(ReqData)), + rabbit_mgmt_util:reply_list( + filter_vhost(status(Chs, ReqData, Context), ReqData), ReqData, Context). + +is_authorized(ReqData, Context) -> + rabbit_mgmt_util:is_authorized_monitor(ReqData, Context). + +%%-------------------------------------------------------------------- + +filter_vhost(List, ReqData) -> + rabbit_mgmt_util:all_or_one_vhost( + ReqData, + fun(V) -> lists:filter(fun(I) -> pget(vhost, I) =:= V end, List) end). + +status(Chs, ReqData, Context) -> + rabbit_mgmt_util:filter_vhost( + lists:append([status(Node, Chs) || Node <- [node() | nodes()]]), + ReqData, Context). + +status(Node, Chs) -> + case rpc:call(Node, rabbit_federation_status, status, [], infinity) of + {badrpc, {'EXIT', {undef, _}}} -> []; + {badrpc, {'EXIT', {noproc, _}}} -> []; + Status -> [format(Node, I, Chs) || I <- Status] + end. + +format(Node, Info, Chs) -> + LocalCh = case rabbit_mgmt_format:strip_pids( + [Ch || Ch <- Chs, + pget(name, pget(connection_details, Ch)) + =:= pget(local_connection, Info)]) of + [Ch] -> [{local_channel, Ch}]; + [] -> [] + end, + [{node, Node} | format_info(Info)] ++ LocalCh. + +format_info(Items) -> + [format_item(I) || I <- Items]. + +format_item({timestamp, {{Y, M, D}, {H, Min, S}}}) -> + {timestamp, print("~w-~2.2.0w-~2.2.0w ~w:~2.2.0w:~2.2.0w", + [Y, M, D, H, Min, S])}; +format_item({error, E}) -> + {error, rabbit_mgmt_format:print("~p", [E])}; +format_item(I) -> + I. + +print(Fmt, Val) -> + list_to_binary(io_lib:format(Fmt, Val)). diff --git a/deps/rabbitmq_federation_management/src/rabbitmq_federation_management.app.src b/deps/rabbitmq_federation_management/src/rabbitmq_federation_management.app.src new file mode 100644 index 0000000..5a66054 --- /dev/null +++ b/deps/rabbitmq_federation_management/src/rabbitmq_federation_management.app.src @@ -0,0 +1,8 @@ +{application, rabbitmq_federation_management, + [{description, "RabbitMQ Federation Management"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {env, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit, rabbitmq_management]} + ]}. diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/CODE_OF_CONDUCT.md b/deps/rabbitmq_jms_topic_exchange/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/CODE_OF_CONDUCT.md rename to deps/rabbitmq_jms_topic_exchange/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_management/CONTRIBUTING.md b/deps/rabbitmq_jms_topic_exchange/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/CONTRIBUTING.md rename to deps/rabbitmq_jms_topic_exchange/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/LICENSE b/deps/rabbitmq_jms_topic_exchange/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/LICENSE rename to deps/rabbitmq_jms_topic_exchange/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/LICENSES.txt b/deps/rabbitmq_jms_topic_exchange/LICENSES.txt similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/LICENSES.txt rename to deps/rabbitmq_jms_topic_exchange/LICENSES.txt diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/Makefile b/deps/rabbitmq_jms_topic_exchange/Makefile similarity index 64% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/Makefile rename to deps/rabbitmq_jms_topic_exchange/Makefile index c5b45c1..d25aaf3 100644 --- a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/Makefile +++ b/deps/rabbitmq_jms_topic_exchange/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_jms_topic_exchange -PROJECT_DESCRIPTION = RabbitMQ JMS topic selector exchange plugin DEPS = rabbit_common rabbit -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client +TEST_DEPS = rabbitmq_ct_helpers amqp_client -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/README.md b/deps/rabbitmq_jms_topic_exchange/README.md similarity index 97% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/README.md rename to deps/rabbitmq_jms_topic_exchange/README.md index f39eede..9d01c9a 100644 --- a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/README.md +++ b/deps/rabbitmq_jms_topic_exchange/README.md @@ -46,6 +46,6 @@ TL;DR: ## Copyright and License -(c) Pivotal Software Inc., 2007-2017. +(c) Pivotal Software Inc., 2007-2016. See [LICENSE](./LICENSE) for license information. diff --git a/deps/rabbitmq_jms_topic_exchange/erlang.mk b/deps/rabbitmq_jms_topic_exchange/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_jms_topic_exchange/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/include/rabbit_jms_topic_exchange.hrl b/deps/rabbitmq_jms_topic_exchange/include/rabbit_jms_topic_exchange.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/include/rabbit_jms_topic_exchange.hrl rename to deps/rabbitmq_jms_topic_exchange/include/rabbit_jms_topic_exchange.hrl diff --git a/deps/rabbitmq_jms_topic_exchange/rabbitmq-components.mk b/deps/rabbitmq_jms_topic_exchange/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_jms_topic_exchange/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl b/deps/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl rename to deps/rabbitmq_jms_topic_exchange/src/rabbit_jms_topic_exchange.erl diff --git a/deps/rabbitmq_jms_topic_exchange/src/rabbitmq_jms_topic_exchange.app.src b/deps/rabbitmq_jms_topic_exchange/src/rabbitmq_jms_topic_exchange.app.src new file mode 100644 index 0000000..8c3e151 --- /dev/null +++ b/deps/rabbitmq_jms_topic_exchange/src/rabbitmq_jms_topic_exchange.app.src @@ -0,0 +1,8 @@ +{ application, rabbitmq_jms_topic_exchange +, [ {description, "RabbitMQ JMS topic selector exchange plugin"} + , {vsn, "3.6.6"} + , {modules, []} + , {registered, []} + , {applications, [kernel, stdlib, rabbit_common, rabbit, mnesia]} + ] +}. diff --git a/rabbitmq-server/deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl b/deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl rename to deps/rabbitmq_jms_topic_exchange/src/sjx_evaluator.erl diff --git a/rabbitmq-server/deps/rabbitmq_management/CODE_OF_CONDUCT.md b/deps/rabbitmq_management/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/CODE_OF_CONDUCT.md rename to deps/rabbitmq_management/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/CONTRIBUTING.md b/deps/rabbitmq_management/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_agent/CONTRIBUTING.md rename to deps/rabbitmq_management/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE b/deps/rabbitmq_management/LICENSE similarity index 82% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE rename to deps/rabbitmq_management/LICENSE index b086024..330ecaa 100644 --- a/rabbitmq-server/deps/rabbitmq_management/LICENSE +++ b/deps/rabbitmq_management/LICENSE @@ -5,7 +5,8 @@ This package makes use of the following third party libraries: jQuery - http://jquery.com/ - MIT license, see LICENSE-MIT-jQuery164 EJS - http://embeddedjs.com/ - MIT license, see LICENSE-MIT-EJS10 Sammy - http://code.quirkey.com/sammy/ - MIT license, see LICENSE-MIT-Sammy060 -Cowboy - http://ninenines.eu/ - ISC license +webmachine - http://webmachine.basho.com/ - Apache license, 2.0 +mochiweb - http://github.com/mochi/mochiweb/ - MIT license base64.js - http://code.google.com/p/stringencoders/ - BSD license, see LICENSE-BSD-base64js If you have any questions regarding licensing, please contact us at info@rabbitmq.com. diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-APACHE2-ExplorerCanvas b/deps/rabbitmq_management/LICENSE-APACHE2-ExplorerCanvas similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-APACHE2-ExplorerCanvas rename to deps/rabbitmq_management/LICENSE-APACHE2-ExplorerCanvas diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-BSD-base64js b/deps/rabbitmq_management/LICENSE-BSD-base64js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-BSD-base64js rename to deps/rabbitmq_management/LICENSE-BSD-base64js diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-EJS10 b/deps/rabbitmq_management/LICENSE-MIT-EJS10 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-EJS10 rename to deps/rabbitmq_management/LICENSE-MIT-EJS10 diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-Flot b/deps/rabbitmq_management/LICENSE-MIT-Flot similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-Flot rename to deps/rabbitmq_management/LICENSE-MIT-Flot diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-Sammy060 b/deps/rabbitmq_management/LICENSE-MIT-Sammy060 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-Sammy060 rename to deps/rabbitmq_management/LICENSE-MIT-Sammy060 diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-jQuery164 b/deps/rabbitmq_management/LICENSE-MIT-jQuery164 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-MIT-jQuery164 rename to deps/rabbitmq_management/LICENSE-MIT-jQuery164 diff --git a/rabbitmq-server/deps/rabbitmq_management/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_management/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_management/LICENSE-MPL-RabbitMQ diff --git a/deps/rabbitmq_management/Makefile b/deps/rabbitmq_management/Makefile new file mode 100644 index 0000000..cc12c49 --- /dev/null +++ b/deps/rabbitmq_management/Makefile @@ -0,0 +1,31 @@ +PROJECT = rabbitmq_management + +DEPS = rabbit_common rabbit amqp_client webmachine rabbitmq_web_dispatch rabbitmq_management_agent +TEST_DEPS = rabbitmq_ct_helpers + +dep_webmachine = git https://github.com/rabbitmq/webmachine.git 6b5210c0ed07159f43222255e05a90bbef6c8cbe +dep_rabbitmq_web_dispatch = git https://github.com/rabbitmq/rabbitmq-web-dispatch.git stable + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-dist.mk \ + rabbit_common/mk/rabbitmq-run.mk \ + rabbit_common/mk/rabbitmq-tools.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk + +# -------------------------------------------------------------------- +# Distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @echo bin/rabbitmqadmin + +prepare-dist:: + $(verbose) sed 's/%%VSN%%/$(VSN)/' bin/rabbitmqadmin \ + > $(EZ_DIR)/priv/www/cli/rabbitmqadmin diff --git a/deps/rabbitmq_management/README.md b/deps/rabbitmq_management/README.md new file mode 100644 index 0000000..fa8bbfe --- /dev/null +++ b/deps/rabbitmq_management/README.md @@ -0,0 +1,13 @@ +# RabbitMQ Management Plugin + +This plugin provides a management UI and HTTP API for RabbitMQ. +This plugin is included in the RabbitMQ distribution. To enable +it, use rabbitmq-plugins. + +## Documentation + +[RabbitMQ management UI documentation](http://www.rabbitmq.com/management.html). + +## Continuous Integration + +[![Build Status](https://travis-ci.org/rabbitmq/rabbitmq-management.svg?branch=master)](https://travis-ci.org/rabbitmq/rabbitmq-management) diff --git a/rabbitmq-server/deps/rabbitmq_management/bin/rabbitmqadmin b/deps/rabbitmq_management/bin/rabbitmqadmin similarity index 91% rename from rabbitmq-server/deps/rabbitmq_management/bin/rabbitmqadmin rename to deps/rabbitmq_management/bin/rabbitmqadmin index 8649739..0b329ad 100755 --- a/rabbitmq-server/deps/rabbitmq_management/bin/rabbitmqadmin +++ b/deps/rabbitmq_management/bin/rabbitmqadmin @@ -14,17 +14,10 @@ # # The Initial Developer of the Original Code is GoPivotal, Inc. # Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -from __future__ import print_function - -try: - from signal import signal, SIGPIPE, SIG_DFL - signal(SIGPIPE, SIG_DFL) -except ImportError: - pass import sys if sys.version_info[0] < 2 or (sys.version_info[0] == 2 and sys.version_info[1] < 6): - eprint("Sorry, rabbitmqadmin requires at least Python 2.6 (2.7.9 when HTTPS is enabled).") + print("Sorry, rabbitmqadmin requires at least Python 2.6 (2.7.9 when HTTPS is enabled).") sys.exit(1) from optparse import OptionParser, TitledHelpFormatter @@ -302,7 +295,7 @@ def make_parser(): help="connect to port PORT", metavar="PORT") add("--path-prefix", dest="path_prefix", - help="use specific URI path prefix for the RabbitMQ HTTP API. /api and operation path will be appended to it. (default: blank string)") + help="use specific URI path prefix for the RabbitMQ HTTP API (default: blank string)") add("-V", "--vhost", dest="vhost", help="connect to vhost VHOST [default: all vhosts for list, '/' for declare]", metavar="VHOST") @@ -312,9 +305,6 @@ def make_parser(): add("-p", "--password", dest="password", help="connect using password PASSWORD", metavar="PASSWORD") - add("-U", "--base-uri", dest="base_uri", - help="connect using a base HTTP API URI. /api and operation path will be appended to it. Path will be ignored. --vhost has to be provided separately.", - metavar="URI") add("-q", "--quiet", action="store_false", dest="verbose", help="suppress status messages") add("-s", "--ssl", action="store_true", dest="ssl", @@ -326,9 +316,7 @@ def make_parser(): add("--ssl-ca-cert-file", dest="ssl_ca_cert_file", help="PEM format CA certificate file for SSL") add("--ssl-disable-hostname-verification", dest="ssl_disable_hostname_verification", - help="Disables peer hostname verification", default=False, action="store_true") - add("-k", "--ssl-insecure", dest="ssl_insecure", - help="Disables all SSL validations like curl's '-k' argument", default=False, action="store_true") + help="Disables peer hostname verification", default=False, action="store_true" ) add("-f", "--format", dest="format", help="format for listing commands - one of [" + ", ".join(FORMATS.keys()) + "]") add("-S", "--sort", dest="sort", help="sort key for listing queries") @@ -393,26 +381,16 @@ def make_configuration(): else: setattr(options, key, val) - # if --base-uri is passed, set connection parameters from it - if options.base_uri is not None: - u = urlparse.urlparse(options.base_uri) - for key in ["hostname", "port", "username", "password"]: - if getattr(u, key) is not None: - setattr(options, key, getattr(u, key)) - - if u.path is not None and (u.path != "") and (u.path != "/"): - eprint("WARNING: path in --base-uri is ignored. Please specify --vhost and/or --path-prefix separately.\n") - return (options, args) def assert_usage(expr, error): if not expr: - eprint("\nERROR: {0}\n".format(error)) - eprint("{0} --help for help\n".format(os.path.basename(sys.argv[0]))) + output("\nERROR: {0}\n".format(error)) + output("{0} --help for help\n".format(os.path.basename(sys.argv[0]))) sys.exit(1) def print_version(): - print("rabbitmqadmin {0}".format(VERSION)) + output("rabbitmqadmin {0}".format(VERSION)) sys.exit(0) def column_sort_key(col): @@ -425,7 +403,7 @@ def main(): (options, args) = make_configuration() if options.bash_completion: print_bash_completion() - sys.exit(0) + exit(0) assert_usage(len(args) > 0, 'Action not specified') mgmt = Management(options, args[1:]) mode = "invoke_" + args[0] @@ -434,28 +412,21 @@ def main(): method = getattr(mgmt, "invoke_%s" % args[0]) method() -def eprint(*args, **kwargs): - print(*args, file=sys.stderr, **kwargs) +def output(s): + print(maybe_utf8(s, sys.stdout)) def die(s): - eprint("*** {0}\n".format(s)) - sys.exit(1) + sys.stderr.write(maybe_utf8("*** {0}\n".format(s), sys.stderr)) + exit(1) -def maybe_utf8(s): - if isinstance(s, int): - # s can be also an int for ex messages count - return str(s) - if isinstance(s, float): - # s can be also a float for message rate - return str(s) - if sys.version_info[0] == 3: +def maybe_utf8(s, stream): + if sys.version_info[0] == 3 or stream.isatty(): # It will have an encoding, which Python will respect return s else: # It won't have an encoding, and Python will pick ASCII by default return s.encode('utf-8') - class Management: def __init__(self, options, args): self.options = options @@ -481,28 +452,19 @@ class Management: # Python < 2.7.8, note: those versions still have SSLv3 enabled # and other limitations. See rabbitmq/rabbitmq-management#225 else: - eprint("WARNING: rabbitmqadmin requires Python 2.7.9+ when HTTPS is used.") + print("Warning: rabbitmqadmin requires Python 2.7.9+ when HTTPS is used.") return httplib.HTTPSConnection(hostname, port, cert_file = self.options.ssl_cert_file, key_file = self.options.ssl_key_file) def __initialize_tls_context(self): # Python 2.7.9+ only - ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) ssl_ctx.options &= ~ssl.OP_NO_SSLv3 - - ssl_insecure = self.options.ssl_insecure - ssl_disable_hostname_verification = ssl_insecure or \ - self.options.ssl_disable_hostname_verification - # Note: you must set check_hostname prior to verify_mode - if ssl_disable_hostname_verification: - ssl_ctx.check_hostname = False - if ssl_insecure: - ssl_ctx.verify_mode = ssl.CERT_NONE - - if self.options.ssl_key_file: - ssl_ctx.load_cert_chain(self.options.ssl_cert_file, - self.options.ssl_key_file) + ssl_ctx.verify_mode = ssl.CERT_REQUIRED + ssl_ctx.check_hostname = not self.options.ssl_disable_hostname_verification + ssl_ctx.load_cert_chain(self.options.ssl_cert_file, + self.options.ssl_key_file) if self.options.ssl_ca_cert_file: ssl_ctx.load_verify_locations(self.options.ssl_ca_cert_file) return ssl_ctx @@ -544,7 +506,7 @@ class Management: def verbose(self, string): if self.options.verbose: - print(string) + output(string) def get_arg(self): assert_usage(len(self.args) == 1, 'Exactly one argument required') @@ -569,7 +531,7 @@ class Management: subcommands config""") print(usage) - sys.exit(0) + exit(0) def invoke_publish(self): (uri, upload) = self.parse_args(self.args, EXTRA_VERBS['publish']) @@ -722,18 +684,18 @@ class Management: try: return json.loads(text) except ValueError: - eprint("ERROR: Could not parse JSON:\n {0}".format(text)) + print("Could not parse JSON:\n {0}".format(text)) sys.exit(1) def format_list(json_list, columns, args, options): format = options.format formatter = None if format == "raw_json": - print(json_list) + output(json_list) return elif format == "pretty_json": enc = json.JSONEncoder(False, False, True, True, True, 2) - print(enc.encode(json.loads(json_list))) + output(enc.encode(json.loads(json_list))) return else: formatter = FORMATS[format] @@ -745,7 +707,7 @@ def format_list(json_list, columns, args, options): class Lister: def verbose(self, string): if self.options.verbose: - print(string) + output(string) def display(self, json_list): depth = sys.maxsize @@ -791,7 +753,7 @@ class Lister: def add_to_row(col, val): if col in column_ix: - row[column_ix[col]] = maybe_utf8(val) + row[column_ix[col]] = str(val) if len(self.columns) == 0: for item in items: @@ -822,7 +784,7 @@ class TSVList(Lister): for row in table: line = "\t".join(row) - print(line) + output(line) class LongList(Lister): def __init__(self, columns, obj_info, options): @@ -836,11 +798,11 @@ class LongList(Lister): for col in columns: max_width = max(max_width, len(col)) fmt = "{0:>" + str(max_width) + "}: {1}" - print(sep) + output(sep) for i in range(0, len(table)): for j in range(0, len(columns)): - print(fmt.format(columns[j], table[i][j])) - print(sep) + output(fmt.format(columns[j], table[i][j])) + output(sep) class TableList(Lister): def __init__(self, columns, obj_info, options): @@ -871,13 +833,13 @@ class TableList(Lister): for i in range(0, len(col_widths)): fmt = " {0:" + align + str(col_widths[i]) + "} " txt += fmt.format(row[i]) + "|" - print(txt) + output(txt) def ascii_bar(self, col_widths): txt = "+" for w in col_widths: txt += ("-" * (w + 2)) + "+" - print(txt) + output(txt) class KeyValueList(Lister): def __init__(self, columns, obj_info, options): @@ -890,7 +852,7 @@ class KeyValueList(Lister): row = [] for j in range(0, len(columns)): row.append("{0}=\"{1}\"".format(columns[j], table[i][j])) - print(" ".join(row)) + output(" ".join(row)) # TODO handle spaces etc in completable names class BashList(Lister): @@ -908,7 +870,7 @@ class BashList(Lister): res = [] for row in table: res.append(row[ix]) - print(" ".join(res)) + output(" ".join(res)) FORMATS = { 'raw_json' : None, # Special cased @@ -1039,7 +1001,7 @@ _rabbitmqadmin() } complete -F _rabbitmqadmin rabbitmqadmin """ - print(script) + output(script) if __name__ == "__main__": main() diff --git a/deps/rabbitmq_management/erlang.mk b/deps/rabbitmq_management/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_management/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_management/include/rabbit_mgmt.hrl b/deps/rabbitmq_management/include/rabbit_mgmt.hrl similarity index 81% rename from rabbitmq-server/deps/rabbitmq_management/include/rabbit_mgmt.hrl rename to deps/rabbitmq_management/include/rabbit_mgmt.hrl index 3177702..a5f6209 100644 --- a/rabbitmq-server/deps/rabbitmq_management/include/rabbit_mgmt.hrl +++ b/deps/rabbitmq_management/include/rabbit_mgmt.hrl @@ -14,4 +14,9 @@ %% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% +-record(context, {user, + password = none, + impl}). % storage for a context of the resource handler +-record(range, {first, last, incr}). + -define(AUTH_REALM, "Basic realm=\"RabbitMQ Management\""). diff --git a/deps/rabbitmq_management/include/rabbit_mgmt_event_collector.hrl b/deps/rabbitmq_management/include/rabbit_mgmt_event_collector.hrl new file mode 100644 index 0000000..816365c --- /dev/null +++ b/deps/rabbitmq_management/include/rabbit_mgmt_event_collector.hrl @@ -0,0 +1,32 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2016 Pivotal Software, Inc. All rights reserved. +%% + +-record(state, { + lookups, + interval, + event_refresh_ref, + rates_mode, + max_backlog}). + +-define(FINE_STATS_TYPES, [channel_queue_stats, channel_exchange_stats, + channel_queue_exchange_stats]). + +-define(TABLES, [queue_stats, connection_stats, channel_stats, + consumers_by_queue, consumers_by_channel, + node_stats, node_node_stats, + %% What the previous info item was for any given + %% {queue/channel/connection} + old_stats]). diff --git a/deps/rabbitmq_management/include/rabbit_mgmt_metrics.hrl b/deps/rabbitmq_management/include/rabbit_mgmt_metrics.hrl new file mode 100644 index 0000000..04ec4c1 --- /dev/null +++ b/deps/rabbitmq_management/include/rabbit_mgmt_metrics.hrl @@ -0,0 +1,211 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. +%% + +-define(DELIVER_GET, [deliver, deliver_no_ack, get, get_no_ack]). +-define(FINE_STATS, [publish, publish_in, publish_out, + ack, deliver_get, confirm, return_unroutable, redeliver] ++ + ?DELIVER_GET). + +%% Most come from channels as fine stats, but queues emit these directly. +-define(QUEUE_MSG_RATES, [disk_reads, disk_writes]). + +-define(MSG_RATES, ?FINE_STATS ++ ?QUEUE_MSG_RATES). + +-define(MSG_RATES_DETAILS, [publish_details, publish_in_details, + publish_out_details, ack_details, + deliver_get_details, confirm_details, + return_unroutable_details, redeliver_details, + deliver_details, deliver_no_ack_details, + get_details, get_no_ack_details, + disk_reads_details, disk_writes_details] ++ ?MSG_RATES). + +-define(QUEUE_MSG_COUNTS, [messages, messages_ready, messages_unacknowledged]). + +-define(COARSE_NODE_STATS, + [mem_used, fd_used, sockets_used, proc_used, disk_free, + io_read_count, io_read_bytes, io_read_time, + io_write_count, io_write_bytes, io_write_time, + io_sync_count, io_sync_time, + io_seek_count, io_seek_time, + io_reopen_count, mnesia_ram_tx_count, mnesia_disk_tx_count, + msg_store_read_count, msg_store_write_count, + queue_index_journal_write_count, + queue_index_write_count, queue_index_read_count, + gc_num, gc_bytes_reclaimed, context_switches, + io_file_handle_open_attempt_count, io_file_handle_open_attempt_time]). + +-define(COARSE_NODE_NODE_STATS, [send_bytes, recv_bytes]). + +%% Normally 0 and no history means "has never happened, don't +%% report". But for these things we do want to report even at 0 with +%% no history. +-define(ALWAYS_REPORT_STATS, + [io_read_time, io_write_time, + io_sync_time, sockets_used | ?QUEUE_MSG_COUNTS]). + +-define(COARSE_CONN_STATS, [recv_oct, send_oct]). + +-define(PROCESS_STATS, [reductions]). + +-type(event_type() :: queue_stats | queue_exchange_stats | vhost_stats + | channel_queue_stats | channel_stats + | channel_exchange_stats | exchange_stats + | node_stats | node_node_stats | connection_stats). +-type(type() :: deliver_get | fine_stats | queue_msg_rates | queue_msg_counts + | coarse_node_stats | coarse_node_node_stats | coarse_conn_stats + | process_stats). + +-type(table_name() :: atom()). + +%% TODO remove unused tables +%% Not all events generate all metrics, so some of the tables may be deleted +-define(AGGR_TABLES, [aggr_queue_stats_fine_stats, + aggr_queue_stats_deliver_get, + aggr_queue_stats_queue_msg_counts, + aggr_queue_stats_queue_msg_rates, + aggr_queue_stats_process_stats, + aggr_queue_exchange_stats_fine_stats, + aggr_vhost_stats_deliver_get, + aggr_vhost_stats_fine_stats, + aggr_vhost_stats_queue_msg_rates, + aggr_vhost_stats_queue_msg_counts, + aggr_vhost_stats_coarse_conn_stats, + aggr_channel_queue_stats_deliver_get, + aggr_channel_queue_stats_fine_stats, + aggr_channel_queue_stats_queue_msg_counts, + aggr_channel_stats_deliver_get, + aggr_channel_stats_fine_stats, + aggr_channel_stats_queue_msg_counts, + aggr_channel_stats_process_stats, + aggr_channel_exchange_stats_deliver_get, + aggr_channel_exchange_stats_fine_stats, + aggr_exchange_stats_fine_stats, + aggr_node_stats_coarse_node_stats, + aggr_node_node_stats_coarse_node_node_stats, + aggr_connection_stats_coarse_conn_stats, + aggr_connection_stats_process_stats + ]). + +-define(INDEX_TABLES, [aggr_queue_stats_fine_stats_index, + aggr_queue_stats_deliver_get_index, + aggr_queue_stats_queue_msg_counts_index, + aggr_queue_stats_queue_msg_rates_index, + aggr_queue_stats_process_stats_index, + aggr_queue_exchange_stats_fine_stats_index, + aggr_vhost_stats_deliver_get_index, + aggr_vhost_stats_fine_stats_index, + aggr_vhost_stats_queue_msg_rates_index, + aggr_vhost_stats_queue_msg_counts_index, + aggr_vhost_stats_coarse_conn_stats_index, + aggr_channel_queue_stats_deliver_get_index, + aggr_channel_queue_stats_fine_stats_index, + aggr_channel_queue_stats_queue_msg_counts_index, + aggr_channel_stats_deliver_get_index, + aggr_channel_stats_fine_stats_index, + aggr_channel_stats_queue_msg_counts_index, + aggr_channel_stats_process_stats_index, + aggr_channel_exchange_stats_deliver_get_index, + aggr_channel_exchange_stats_fine_stats_index, + aggr_exchange_stats_fine_stats_index, + aggr_node_stats_coarse_node_stats_index, + aggr_node_node_stats_coarse_node_node_stats_index, + aggr_connection_stats_coarse_conn_stats_index, + aggr_connection_stats_process_stats_index + ]). + +-define(KEY_INDEX_TABLES, + [aggr_queue_stats_fine_stats_key_index, + aggr_queue_stats_deliver_get_key_index, + aggr_queue_stats_queue_msg_counts_key_index, + aggr_queue_stats_queue_msg_rates_key_index, + aggr_queue_stats_process_stats_key_index, + aggr_queue_exchange_stats_fine_stats_key_index, + aggr_vhost_stats_deliver_get_key_index, + aggr_vhost_stats_fine_stats_key_index, + aggr_vhost_stats_queue_msg_rates_key_index, + aggr_vhost_stats_queue_msg_counts_key_index, + aggr_vhost_stats_coarse_conn_stats_key_index, + aggr_channel_queue_stats_deliver_get_key_index, + aggr_channel_queue_stats_fine_stats_key_index, + aggr_channel_queue_stats_queue_msg_counts_key_index, + aggr_channel_stats_deliver_get_key_index, + aggr_channel_stats_fine_stats_key_index, + aggr_channel_stats_queue_msg_counts_key_index, + aggr_channel_stats_process_stats_key_index, + aggr_channel_exchange_stats_deliver_get_key_index, + aggr_channel_exchange_stats_fine_stats_key_index, + aggr_exchange_stats_fine_stats_key_index, + aggr_node_stats_coarse_node_stats_key_index, + aggr_node_node_stats_coarse_node_node_stats_key_index, + aggr_connection_stats_coarse_conn_stats_key_index, + aggr_connection_stats_process_stats_key_index + ]). + +-define(PROC_STATS_TABLES, + [channel_stats, connection_stats]). + +%% Records are only used to retrieve the field position and to facilitate +%% keeping track of the data +-record(deliver_get, {deliver, + deliver_no_ack, + get, + get_no_ack}). +-record(fine_stats, {publish, + publish_in, + publish_out, + ack, + deliver_get, + confirm, + return_unroutable, + redeliver}). +-record(queue_msg_rates, {disk_reads, + disk_writes}). +-record(queue_msg_counts, {messages, + messages_ready, + messages_unacknowledged}). +-record(coarse_node_stats, {mem_used, + fd_used, + sockets_used, + proc_used, + disk_free, + io_read_count, + io_read_bytes, + io_read_time, + io_write_count, + io_write_bytes, + io_write_time, + io_sync_count, + io_sync_time, + io_seek_count, + io_seek_time, + io_reopen_count, + mnesia_ram_tx_count, + mnesia_disk_tx_count, + msg_store_read_count, + msg_store_write_count, + queue_index_journal_write_count, + queue_index_write_count, + queue_index_read_count, + gc_num, + gc_bytes_reclaimed, + context_switches, + io_file_handle_open_attempt_count, + io_file_handle_open_attempt_time}). +-record(coarse_node_node_stats, {send_bytes, + recv_bytes}). +-record(coarse_conn_stats, {recv_oct, + send_oct}). +-record(process_stats, {reductions}). diff --git a/deps/rabbitmq_management/include/rabbit_mgmt_test.hrl b/deps/rabbitmq_management/include/rabbit_mgmt_test.hrl new file mode 100644 index 0000000..dca669d --- /dev/null +++ b/deps/rabbitmq_management/include/rabbit_mgmt_test.hrl @@ -0,0 +1,11 @@ +-include_lib("eunit/include/eunit.hrl"). +-include_lib("amqp_client/include/amqp_client.hrl"). + +-define(OK, 200). +-define(CREATED, 201). +-define(NO_CONTENT, 204). +-define(BAD_REQUEST, 400). +-define(NOT_AUTHORISED, 401). +%%-define(NOT_FOUND, 404). Defined for AMQP by amqp_client.hrl (as 404) +%% httpc seems to get racy when using HTTP 1.1 +-define(HTTPC_OPTS, [{version, "HTTP/1.0"}]). diff --git a/rabbitmq-server/deps/rabbitmq_management/license_info b/deps/rabbitmq_management/license_info similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/license_info rename to deps/rabbitmq_management/license_info diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/api/index.html b/deps/rabbitmq_management/priv/www/api/index.html similarity index 90% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/api/index.html rename to deps/rabbitmq_management/priv/www/api/index.html index 60a00ef..1cb9ed5 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/api/index.html +++ b/deps/rabbitmq_management/priv/www/api/index.html @@ -54,9 +54,9 @@ list of subfields separated by dots. See the example below.

Most of the GET queries return many fields per - object. See the separate stats + object. See the separate stats documentation.

- +

Examples

A few quick examples for Windows and Unix, using the command line @@ -570,21 +570,14 @@ Content-Length: 0 X /api/bindings/vhost/e/exchange/q/queue - -

- A list of all bindings between an exchange and a - queue. Remember, an exchange and a queue can be bound - together many times! -

-

- To create a new binding, POST to this - URI. Request body should be a JSON object optionally containing - two fields, routing_key (a string) and arguments (a map of optional arguments): -

{"routing_key":"my_routing_key", "arguments":{"x-arg": "value"}}
- All keys are optional. - The response will contain a Location header - telling you the URI of your new binding. -

+ A list of all bindings between an exchange and a + queue. Remember, an exchange and a queue can be bound + together many times! To create a new binding, POST to this + URI. You will need a body looking something like this: +
{"routing_key":"my_routing_key","arguments":{}}
+ All keys are optional. + The response will contain a Location header + telling you the URI of your new binding. @@ -595,9 +588,7 @@ Content-Length: 0 /api/bindings/vhost/e/exchange/q/queue/props An individual binding between an exchange and a queue. The props part of the URI is a "name" for the binding - composed of its routing key and a hash of its - arguments. props is the field named "properties_key" - from a bindings listing response. + composed of its routing key and a hash of its arguments. X @@ -606,22 +597,9 @@ Content-Length: 0 X /api/bindings/vhost/e/source/e/destination -

- A list of all bindings between two exchanges, similar to + A list of all bindings between two exchanges. Similar to the list of all bindings between an exchange and a queue, above. -

-

-

- To create a new binding, POST to this - URI. Request body should be a JSON object optionally containing - two fields, routing_key (a string) and arguments (a map of optional arguments): -

{"routing_key":"my_routing_key", "arguments":{"x-arg": "value"}}
- All keys are optional. - The response will contain a Location header - telling you the URI of your new binding. -

-

@@ -683,12 +661,10 @@ or:
{"password_hash":"2lmoth8l4H0DViLaK9Fxi6l9ds8=", "tags":"administrator"}
The tags key is mandatory. Either password or password_hash - must be set. Setting password_hash to "" will ensure the + must be set. Setting password_hash to "" will ensure the user cannot use a password to log in. tags is a comma-separated list of tags for the user. Currently recognised tags - are administrator, monitoring and management. - password_hash must be generated using the algorithm described - here. + are "administrator", "monitoring" and "management". @@ -731,7 +707,7 @@ or: /api/parameters - A list of all vhost-scoped parameters. + A list of all parameters. X @@ -739,7 +715,7 @@ or: /api/parameters/component - A list of all vhost-scoped parameters for a given component. + A list of all parameters for a given component. X @@ -747,7 +723,7 @@ or: /api/parameters/component/vhost - A list of all vhost-scoped parameters for a given component and virtual host. + A list of all parameters for a given component and virtual host. X @@ -755,27 +731,10 @@ or: X /api/parameters/component/vhost/name - An individual vhost-scoped parameter. To PUT a parameter, you will need a body looking something like this: + An individual parameter. To PUT a parameter, you will need a body looking something like this:
{"vhost": "/","component":"federation","name":"local_username","value":"guest"}
- - X - - - - /api/global-parameters - A list of all global parameters. - - - X - X - X - - /api/global-parameters/name - An individual global parameter. To PUT a parameter, you will need a body looking something like this: -
{"name":"user_vhost_mapping","value":{"guest":"/","rabbit":"warren"}}
- X diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/cli/index.html b/deps/rabbitmq_management/priv/www/cli/index.html similarity index 81% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/cli/index.html rename to deps/rabbitmq_management/priv/www/cli/index.html index 35823f0..5c2e1cc 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/cli/index.html +++ b/deps/rabbitmq_management/priv/www/cli/index.html @@ -11,12 +11,11 @@

rabbitmqadmin

- Download it from here (Right click, + Download it from here (Right click, Save as), make executable, and drop it in your path. Note that many browsers will rename the file rabbitmqadmin.txt. You will need Python - 2.6 or later. To use rabbitmqadmin with HTTPS, - Python 2.6.7 is the minimum supported version. + 2.x, 2.6 or later (i.e. not Python 3).

diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/css/evil.css b/deps/rabbitmq_management/priv/www/css/evil.css similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/css/evil.css rename to deps/rabbitmq_management/priv/www/css/evil.css diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/css/main.css b/deps/rabbitmq_management/priv/www/css/main.css similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/css/main.css rename to deps/rabbitmq_management/priv/www/css/main.css diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/doc/stats.html b/deps/rabbitmq_management/priv/www/doc/stats.html similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/doc/stats.html rename to deps/rabbitmq_management/priv/www/doc/stats.html diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/favicon.ico b/deps/rabbitmq_management/priv/www/favicon.ico similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/favicon.ico rename to deps/rabbitmq_management/priv/www/favicon.ico diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-binary.png b/deps/rabbitmq_management/priv/www/img/bg-binary.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-binary.png rename to deps/rabbitmq_management/priv/www/img/bg-binary.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-green-dark.png b/deps/rabbitmq_management/priv/www/img/bg-green-dark.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-green-dark.png rename to deps/rabbitmq_management/priv/www/img/bg-green-dark.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-red-dark.png b/deps/rabbitmq_management/priv/www/img/bg-red-dark.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-red-dark.png rename to deps/rabbitmq_management/priv/www/img/bg-red-dark.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-red.png b/deps/rabbitmq_management/priv/www/img/bg-red.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-red.png rename to deps/rabbitmq_management/priv/www/img/bg-red.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-yellow-dark.png b/deps/rabbitmq_management/priv/www/img/bg-yellow-dark.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/bg-yellow-dark.png rename to deps/rabbitmq_management/priv/www/img/bg-yellow-dark.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/collapse.png b/deps/rabbitmq_management/priv/www/img/collapse.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/collapse.png rename to deps/rabbitmq_management/priv/www/img/collapse.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/expand.png b/deps/rabbitmq_management/priv/www/img/expand.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/expand.png rename to deps/rabbitmq_management/priv/www/img/expand.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/img/rabbitmqlogo.png b/deps/rabbitmq_management/priv/www/img/rabbitmqlogo.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/img/rabbitmqlogo.png rename to deps/rabbitmq_management/priv/www/img/rabbitmqlogo.png diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/index.html b/deps/rabbitmq_management/priv/www/index.html similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/index.html rename to deps/rabbitmq_management/priv/www/index.html diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/base64.js b/deps/rabbitmq_management/priv/www/js/base64.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/base64.js rename to deps/rabbitmq_management/priv/www/js/base64.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/charts.js b/deps/rabbitmq_management/priv/www/js/charts.js similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/charts.js rename to deps/rabbitmq_management/priv/www/js/charts.js index 54c482d..cccbc4c 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/charts.js +++ b/deps/rabbitmq_management/priv/www/js/charts.js @@ -3,16 +3,14 @@ // function message_rates(id, stats) { - var items = [['Publish', 'publish'], - ['Publisher confirm', 'confirm'], + var items = [['Publish', 'publish'], ['Confirm', 'confirm'], ['Publish (In)', 'publish_in'], ['Publish (Out)', 'publish_out'], - ['Deliver (manual ack)', 'deliver'], - ['Deliver (auto ack)', 'deliver_no_ack'], - ['Consumer ack', 'ack'], + ['Deliver', 'deliver'], ['Redelivered', 'redeliver'], - ['Get (manual ack)', 'get'], - ['Get (auto ack)', 'get_no_ack'], + ['Acknowledge', 'ack'], + ['Get', 'get'], ['Deliver (noack)', 'deliver_no_ack'], + ['Get (noack)', 'get_no_ack'], ['Return', 'return_unroutable'], ['Disk read', 'disk_reads'], ['Disk write', 'disk_writes']]; diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/dispatcher.js b/deps/rabbitmq_management/priv/www/js/dispatcher.js similarity index 95% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/dispatcher.js rename to deps/rabbitmq_management/priv/www/js/dispatcher.js index 4a76cc1..8cec43d 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/dispatcher.js +++ b/deps/rabbitmq_management/priv/www/js/dispatcher.js @@ -67,7 +67,7 @@ dispatcher_add(function(sammy) { sammy.get('#/exchanges', function() { - renderExchanges(); + renderExchanges() }); @@ -226,9 +226,7 @@ dispatcher_add(function(sammy) { }); sammy.put('#/logout', function() { - // clear a local storage value used by earlier versions clear_pref('auth'); - clear_cookie_value('auth'); location.reload(); }); @@ -241,14 +239,4 @@ dispatcher_add(function(sammy) { sammy.put('#/column-options', function() { update_column_options(this); }); - sammy.del("#/reset", function(){ - if(sync_delete(this, '/reset')){ - update(); - } - }); - sammy.del("#/reset_node", function(){ - if(sync_delete(this, '/reset/:node')){ - update(); - } - }); }); diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/ejs.js b/deps/rabbitmq_management/priv/www/js/ejs.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/ejs.js rename to deps/rabbitmq_management/priv/www/js/ejs.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/ejs.min.js b/deps/rabbitmq_management/priv/www/js/ejs.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/ejs.min.js rename to deps/rabbitmq_management/priv/www/js/ejs.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/excanvas.js b/deps/rabbitmq_management/priv/www/js/excanvas.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/excanvas.js rename to deps/rabbitmq_management/priv/www/js/excanvas.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/excanvas.min.js b/deps/rabbitmq_management/priv/www/js/excanvas.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/excanvas.min.js rename to deps/rabbitmq_management/priv/www/js/excanvas.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/formatters.js b/deps/rabbitmq_management/priv/www/js/formatters.js similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/formatters.js rename to deps/rabbitmq_management/priv/www/js/formatters.js index 391575e..a6cff81 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/formatters.js +++ b/deps/rabbitmq_management/priv/www/js/formatters.js @@ -91,6 +91,11 @@ function fmt_features_short(obj) { var res = ''; var features = args_to_features(obj); + if (obj.owner_pid_details != undefined) { + res += '' + + link_conn(obj.owner_pid_details.name, "Excl") + ' '; + } + for (var k in ALL_ARGS) { if (features[k] != undefined) { res += '/gm, ''); -} - function fmt_escape_html(txt) { return fmt_escape_html0(txt).replace(/\n/g, '
'); } @@ -457,14 +449,7 @@ function fmt_escape_html_one_line(txt) { } function fmt_escape_html0(txt) { - if(txt === null) { - return ""; - } - if(txt === undefined) { - return ""; - } - - return ("" + txt).replace(/&/g, '&') + return txt.replace(/&/g, '&') .replace(//g, '>') .replace(/\"/g, '"'); @@ -520,7 +505,7 @@ function fmt_object_state(obj) { } else if (obj.state == 'flow') { colour = 'yellow'; - explanation = 'Publishing rate recently throttled by server.'; + explanation = 'Publishing rate recently restricted by server.'; } else if (obj.state == 'down') { colour = 'red'; @@ -711,7 +696,7 @@ function filter_ui_pg(items, truncate, appendselect) { var selected = current_filter == '' ? (items_desc(items.length)) : (items.length + ' of ' + items_desc(total) + ' selected'); - + selected += appendselect; res += '

' + selected + @@ -727,7 +712,7 @@ function filter_ui(items) { parseInt(get_pref('truncate')) : current_truncate; var truncate_input = ''; - var selected = ''; + var selected = ''; if (items.length > current_truncate) { selected += ' ' + '(only showing first '; @@ -774,9 +759,9 @@ function pagiante_ui(pages, context){ res += '' ; res += ' (?)' ; - + + res += fmt_regex_request(context, "") + '> (?)' ; + res +=' ' ; res += '

'; res += ' '; @@ -871,20 +856,20 @@ function properties_size(obj) { if (obj.hasOwnProperty(k)) count++; } return count; -} +} function frm_default_value(template, defaultValue){ var store_value = get_pref(template); - var result = (((store_value == null) - || (store_value == undefined) - || (store_value == '')) ? defaultValue : + var result = (((store_value == null) + || (store_value == undefined) + || (store_value == '')) ? defaultValue : store_value); return ((result == undefined) ? defaultValue : result); } function fmt_page_number_request(template, defaultPage){ - if ((defaultPage == undefined) || (defaultPage <= 0)) + if ((defaultPage == undefined) || (defaultPage <= 0)) defaultPage = 1; return frm_default_value(template + '_current_page_number', defaultPage); } diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/global.js b/deps/rabbitmq_management/priv/www/js/global.js similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/global.js rename to deps/rabbitmq_management/priv/www/js/global.js index f96f9c3..29bce6a 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/global.js +++ b/deps/rabbitmq_management/priv/www/js/global.js @@ -21,14 +21,12 @@ var KNOWN_ARGS = {'alternate-exchange': {'short': 'AE', 'type': 'string' 'x-max-length-bytes': {'short': 'Lim B', 'type': 'int'}, 'x-dead-letter-exchange': {'short': 'DLX', 'type': 'string'}, 'x-dead-letter-routing-key': {'short': 'DLK', 'type': 'string'}, - 'x-queue-master-locator': {'short': 'ML', 'type': 'string'}, 'x-max-priority': {'short': 'Pri', 'type': 'int'}}; // Things that are like arguments that we format the same way in listings. -var IMPLICIT_ARGS = {'durable': {'short': 'D', 'type': 'boolean'}, - 'auto-delete': {'short': 'AD', 'type': 'boolean'}, - 'exclusive': {'short': 'Excl', 'type': 'boolean'}, - 'internal': {'short': 'I', 'type': 'boolean'}}; +var IMPLICIT_ARGS = {'durable': {'short': 'D', 'type': 'boolean'}, + 'auto-delete': {'short': 'AD', 'type': 'boolean'}, + 'internal': {'short': 'I', 'type': 'boolean'}}; // Both the above var ALL_ARGS = {}; diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/help.js b/deps/rabbitmq_management/priv/www/js/help.js similarity index 94% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/help.js rename to deps/rabbitmq_management/priv/www/js/help.js index eab13f0..603a48d 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/help.js +++ b/deps/rabbitmq_management/priv/www/js/help.js @@ -32,12 +32,6 @@ HELP = { 'queue-max-priority': 'Maximum number of priority levels for the queue to support; if not set, the queue will not support message priorities.
(Sets the "x-max-priority" argument.)', - 'queue-lazy': - 'Set the queue into lazy mode, keeping as many messages as possible on disk to reduce RAM usage; if not set, the queue will keep an in-memory cache to deliver messages as fast as possible.
(Sets the "x-queue-mode" argument.)', - - 'queue-master-locator': - 'Set the queue into master location mode, determining the rule by which the queue master is located when declared on a cluster of nodes.
(Sets the "x-queue-master-locator" argument.)', - 'queue-messages': '

Message counts.

Note that "in memory" and "persistent" are not mutually exclusive; persistent messages can be in memory as well as on disc, and transient messages can be paged out if memory is tight. Non-durable queues will consider all messages to be transient.

', @@ -216,20 +210,20 @@ HELP = {
\
Publish
\
Rate at which messages are entering the server.
\ -
Publisher confirm
\ +
Confirm
\
Rate at which the server is confirming publishes.
\ -
Deliver (manual ack)
\ -
Rate at which messages are delivered to consumers that use manual acknowledgements.
\ -
Deliver (auto ack)
\ -
Rate at which messages are delivered to consumers that use automatic acknowledgements.
\ -
Consumer ack
\ -
Rate at which messages are being acknowledged by consumers.
\ -
Redelivered
\ -
Rate at which messages with the \'redelivered\' flag set are being delivered. Note that these messages will also be counted in one of the delivery rates above.
\ -
Get (manual ack)
\ +
Deliver
\ +
Rate at which messages requiring acknowledgement are being delivered in response to basic.consume.
\ +
Deliver (noack)
\ +
Rate at which messages not requiring acknowledgement are being delivered in response to basic.consume.
\ +
Get
\
Rate at which messages requiring acknowledgement are being delivered in response to basic.get.
\ -
Get (auto ack)
\ +
Get (noack)
\
Rate at which messages not requiring acknowledgement are being delivered in response to basic.get.
\ +
Acknowledge
\ +
Rate at which messages are being acknowledged.
\ +
Redelivered
\ +
Rate at which messages with the \'redelivered\' flag set are being delivered. Note that these messages will also be counted in one of the delivery rates above.
\
Return
\
Rate at which basic.return is sent to publishers for unroutable messages published with the \'mandatory\' flag set.
\
Disk read
\ diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.js b/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.js rename to deps/rabbitmq_management/priv/www/js/jquery-1.6.4.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.min.js b/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery-1.6.4.min.js rename to deps/rabbitmq_management/priv/www/js/jquery-1.6.4.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.js b/deps/rabbitmq_management/priv/www/js/jquery.flot.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.js rename to deps/rabbitmq_management/priv/www/js/jquery.flot.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.min.js b/deps/rabbitmq_management/priv/www/js/jquery.flot.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.min.js rename to deps/rabbitmq_management/priv/www/js/jquery.flot.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.time.js b/deps/rabbitmq_management/priv/www/js/jquery.flot.time.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.time.js rename to deps/rabbitmq_management/priv/www/js/jquery.flot.time.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.time.min.js b/deps/rabbitmq_management/priv/www/js/jquery.flot.time.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/jquery.flot.time.min.js rename to deps/rabbitmq_management/priv/www/js/jquery.flot.time.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/json2.js b/deps/rabbitmq_management/priv/www/js/json2.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/json2.js rename to deps/rabbitmq_management/priv/www/js/json2.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/main.js b/deps/rabbitmq_management/priv/www/js/main.js similarity index 91% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/main.js rename to deps/rabbitmq_management/priv/www/js/main.js index ef25252..03a3274 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/main.js +++ b/deps/rabbitmq_management/priv/www/js/main.js @@ -17,14 +17,8 @@ function dispatcher() { } function set_auth_pref(userinfo) { - // clear a local storage value used by earlier versions - clear_local_pref('auth'); - var b64 = b64_encode_utf8(userinfo); - var date = new Date(); - // 8 hours from now - date.setHours(date.getHours() + 8); - store_cookie_value_with_expiration('auth', encodeURIComponent(b64), date); + store_pref('auth', encodeURIComponent(b64)); } function login_route () { @@ -64,7 +58,7 @@ function start_app_login() { this.get(/\#\/login\/(.*)/, login_route_with_path); }); app.run(); - if (get_cookie_value('auth') != null) { + if (get_pref('auth') != null) { check_login(); } } @@ -72,9 +66,7 @@ function start_app_login() { function check_login() { user = JSON.parse(sync_get('/whoami')); if (user == false) { - // clear a local storage value used by earlier versions clear_pref('auth'); - clear_cookie_value('auth'); replace_content('login-status', '

Login failed

'); } else { @@ -268,8 +260,7 @@ function partial_update() { var befores = $('#main .updatable'); var afters = $('#scratch .updatable'); if (befores.length != afters.length) { - console.log("before/after mismatch! Doing a full reload..."); - full_refresh(); + throw("before/after mismatch"); } for (var i = 0; i < befores.length; i++) { $(befores[i]).empty().append($(afters[i]).contents()); @@ -404,15 +395,11 @@ function y_position() { } function with_update(fun) { - if(outstanding_reqs.length > 0){ - return false; - } with_reqs(apply_state(current_reqs), [], function(json) { var html = format(current_template, json); fun(html); update_status('ok'); }); - return true; } function apply_state(reqs) { @@ -521,32 +508,15 @@ function show_popup(type, text, mode) { -function submit_import(form) { - if (form.file.value) { - var confirm_upload = confirm('Are you sure you want to import a definitions file? Some entities (vhosts, users, queues, etc) may be overwritten!'); - if (confirm_upload === true) { - var idx = $("select[name='vhost-upload'] option:selected").index(); - var vhost = ((idx <= 0) ? "" : "/" + esc($("select[name='vhost-upload'] option:selected").val())); - form.action ="api/definitions" + vhost + '?auth=' + get_cookie_value('auth'); - form.submit(); - window.location.replace("../../#/import-succeeded"); - } else { - return false; - } - } else { - return false; - } -}; + function submit_import(form) { + var idx = $("select[name='vhost-upload'] option:selected").index() + var vhost = ((idx <=0 ) ? "" : "/" + esc($("select[name='vhost-upload'] option:selected").val())); + form.action ="api/definitions" + vhost + '?auth=' + get_pref('auth'); + form.submit(); + }; function postprocess() { - $('form.confirm-queue').submit(function() { - return confirm("Are you sure? The queue is going to be deleted. " + - "Messages cannot be recovered after deletion."); - }); - $('form.confirm-purge-queue').submit(function() { - return confirm("Are you sure? Messages cannot be recovered after purging."); - }); $('form.confirm').submit(function() { return confirm("Are you sure? This object cannot be recovered " + "after deletion."); @@ -565,11 +535,11 @@ function postprocess() { } }); $('#download-definitions').click(function() { - var idx = $("select[name='vhost-download'] option:selected").index(); + var idx = $("select[name='vhost-download'] option:selected").index() var vhost = ((idx <=0 ) ? "" : "/" + esc($("select[name='vhost-download'] option:selected").val())); var path = 'api/definitions' + vhost + '?download=' + esc($('#download-filename').val()) + - '&auth=' + get_cookie_value('auth'); + '&auth=' + get_pref('auth'); window.location = path; setTimeout('app.run()'); return false; @@ -634,10 +604,8 @@ function postprocess() { var field = $(this).attr('field'); var row = $('#' + field).find('.mf').last(); var key = row.find('input').first(); - var value = row.find('input').last(); var type = row.find('select').last(); key.val($(this).attr('key')); - value.val($(this).attr('value')); type.val($(this).attr('type')); update_multifields(); }); @@ -656,24 +624,17 @@ function postprocess() { function url_pagination_template(template, defaultPage, defaultPageSize){ - var page_number_request = fmt_page_number_request(template, defaultPage); - var page_size = fmt_page_size_request(template, defaultPageSize); - var name_request = fmt_filter_name_request(template, ""); - var use_regex = fmt_regex_request(template, "") == "checked"; - if (use_regex) { - name_request = esc(name_request); - } - return '/' + template + - '?page=' + page_number_request + - '&page_size=' + page_size + - '&name=' + name_request + - '&use_regex=' + use_regex; + return '/' + template + '?page=' + fmt_page_number_request(template, defaultPage) + + '&page_size=' + fmt_page_size_request(template, defaultPageSize) + + '&name=' + fmt_filter_name_request(template, "") + + '&use_regex=' + ((fmt_regex_request(template,"") == "checked" ? 'true' : 'false')); + } function stored_page_info(template, page_start){ - var pageSize = fmt_strip_tags($('#' + template+'-pagesize').val()); - var filterName = fmt_strip_tags($('#' + template+'-name').val()); + var pageSize = $('#' + template+'-pagesize').val(); + var filterName = $('#' + template+'-name').val(); store_pref(template + '_current_page_number', page_start); if (filterName != null && filterName != undefined) { @@ -729,10 +690,7 @@ function renderChannels() { function update_pages_from_ui(sender) { - var val = $(sender).val(); - var raw = !!$(sender).attr('data-page-start') ? $(sender).attr('data-page-start') : val; - var s = fmt_strip_tags(raw); - update_pages(current_template, s); + update_pages(current_template, !!$(sender).attr('data-page-start') ? $(sender).attr('data-page-start') : $(sender).val()); } function postprocess_partial() { @@ -863,7 +821,7 @@ function update_filter_regex(jElem) { current_filter_regex = new RegExp(current_filter,'i'); } catch (e) { jElem.parents('.filter').append('

' + - fmt_escape_html(e.message) + '

'); + e.message + '

'); } } } @@ -946,16 +904,7 @@ function toggle_visibility(item) { } function publish_msg(params0) { - try { - var params = params_magic(params0); - publish_msg0(params); - } catch (e) { - show_popup('warn', fmt_escape_html(e)); - return false; - } -} - -function publish_msg0(params) { + var params = params_magic(params0); var path = fill_path_template('/exchanges/:vhost/:name/publish', params); params['payload_encoding'] = 'string'; params['properties'] = {}; @@ -1041,9 +990,7 @@ function format(template, json) { return tmpl.render(json); } catch (err) { clearInterval(timer); - console.log("Uncaught error: " + err); - console.log("Stack: " + err['stack']); - debug(err['name'] + ": " + err['message'] + "\n" + err['stack'] + "\n"); + debug(err['name'] + ": " + err['message']); } } @@ -1064,25 +1011,11 @@ function update_status(status) { replace_content('status', html); } -function has_auth_cookie_value() { - return get_cookie_value('auth') != null; -} - function auth_header() { - if(has_auth_cookie_value()) { - return "Basic " + decodeURIComponent(get_cookie_value('auth')); - } else { - return null; - } + return "Basic " + decodeURIComponent(get_pref('auth')); } function with_req(method, path, body, fun) { - if(!has_auth_cookie_value()) { - // navigate to the login form - location.reload(); - return; - } - var json; var req = xmlHttpRequest(); req.open(method, 'api' + path, true ); @@ -1127,7 +1060,7 @@ function sync_req(type, params0, path_template, options) { params = params_magic(params0); path = fill_path_template(path_template, params); } catch (e) { - show_popup('warn', fmt_escape_html(e)); + show_popup('warn', e); return false; } var req = xmlHttpRequest(); @@ -1185,8 +1118,8 @@ function check_bad_response(req, full_page_404) { var error = JSON.parse(req.responseText).error; if (typeof(error) != 'string') error = JSON.stringify(error); - if (error == 'bad_request' || error == 'not_found' || error == 'not_authorised') { - show_popup('warn', fmt_escape_html(reason)); + if (error == 'bad_request' || error == 'not_found') { + show_popup('warn', reason); } else if (error == 'page_out_of_range') { var seconds = 60; if (last_page_out_of_range_error > 0) diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/prefs.js b/deps/rabbitmq_management/priv/www/js/prefs.js similarity index 79% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/prefs.js rename to deps/rabbitmq_management/priv/www/js/prefs.js index 512a7ed..d0cccb2 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/prefs.js +++ b/deps/rabbitmq_management/priv/www/js/prefs.js @@ -8,30 +8,6 @@ function local_storage_available() { } } -function store_cookie_value(k, v) { - var d = parse_cookie(); - d[short_key(k)] = v; - store_cookie(d); -} - -function store_cookie_value_with_expiration(k, v, expiration_date) { - var d = parse_cookie(); - d[short_key(k)] = v; - store_cookie_with_expiration(d, expiration_date); -} - -function clear_cookie_value(k) { - var d = parse_cookie(); - delete d[short_key(k)]; - store_cookie(d); -} - -function get_cookie_value(k) { - var r; - r = parse_cookie()[short_key(k)]; - return r == undefined ? default_pref(k) : r; -} - function store_pref(k, v) { if (local_storage_available()) { window.localStorage['rabbitmq.' + k] = v; @@ -52,12 +28,7 @@ function clear_pref(k) { delete d[short_key(k)]; store_cookie(d); } -} -function clear_local_pref(k) { - if (local_storage_available()) { - window.localStorage.removeItem('rabbitmq.' + k); - } } function get_pref(k) { @@ -124,17 +95,13 @@ function parse_cookie() { } function store_cookie(dict) { - var date = new Date(); - date.setFullYear(date.getFullYear() + 1); - store_cookie_with_expiration(dict, date); -} - -function store_cookie_with_expiration(dict, expiration_date) { var enc = []; for (var k in dict) { enc.push(k + ':' + escape(dict[k])); } - document.cookie = 'm=' + enc.join('|') + '; expires=' + expiration_date.toUTCString(); + var date = new Date(); + date.setFullYear(date.getFullYear() + 1); + document.cookie = 'm=' + enc.join('|') + '; expires=' + date.toUTCString(); } function get_cookie(key) { diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/sammy.js b/deps/rabbitmq_management/priv/www/js/sammy.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/sammy.js rename to deps/rabbitmq_management/priv/www/js/sammy.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/sammy.min.js b/deps/rabbitmq_management/priv/www/js/sammy.min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/sammy.min.js rename to deps/rabbitmq_management/priv/www/js/sammy.min.js diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/404.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/404.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/404.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/404.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/add-binding.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/add-binding.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/add-binding.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/add-binding.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/binary.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/binary.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/binary.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/binary.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/bindings.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/bindings.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/bindings.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/bindings.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channel.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/channel.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channel.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/channel.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/channels-list.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channels.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/channels.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/channels.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/channels.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/cluster-name.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/cluster-name.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/cluster-name.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/cluster-name.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/columns-options.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/columns-options.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/columns-options.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/columns-options.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/connection.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/connection.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/connection.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/connection.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/connections.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/consumers.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/error-popup.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/error-popup.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/error-popup.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/error-popup.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/exchange.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/exchange.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/exchange.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/exchange.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs index adb521b..b7760ee 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/exchanges.ejs @@ -91,7 +91,7 @@ diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/import-succeeded.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/import-succeeded.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/import-succeeded.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/import-succeeded.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/layout.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/layout.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/layout.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/layout.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/login.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/login.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/login.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/login.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory-bar.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/memory-bar.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory-bar.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/memory-bar.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory-table.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/memory-table.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory-table.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/memory-table.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/memory.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/messages.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/messages.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/messages.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/messages.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-deliveries.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/msg-detail-publishes.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/node.ejs index 2ed39c8..8cd71bb 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/node.ejs @@ -298,19 +298,6 @@ [['Context switches', 'context_switches']], fmt_rate, fmt_rate_axis, true, 'Context switch operations', 'context-switches-operations') %> -
-

Management GC queue length

- - <% for(var k in node.metrics_gc_queue_length) { - if(node.metrics_gc_queue_length.hasOwnProperty(k)) { %> - - - - - <% } } %> -
<%= k %><%= node.metrics_gc_queue_length[k] %>
-
-

All applications

diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs similarity index 92% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs index 60dbb25..42bac23 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/overview.ejs @@ -22,10 +22,14 @@

Totals

-<%= queue_lengths('lengths-over', overview.queue_totals) %> +<% if (overview.statistics_db_node != 'not_running') { %> + <%= queue_lengths('lengths-over', overview.queue_totals) %> <% if (rates_mode != 'none') { %> <%= message_rates('msg-rates-over', overview.message_stats) %> <% } %> +<% } else { %> + Totals not available +<% } %> <% if (overview.object_totals) { %>

Global counts

@@ -104,9 +108,6 @@ <% } %> <% if (show_column('overview', 'info')) { %>
- <% } %> - <% if (user_administrator) { %> - <% } %> @@ -198,25 +199,19 @@ RAM <% } %> <%= fmt_plugins_small(node) %> + <% if (overview.statistics_db_node == node.name) { %> + Stats + <% } %> <% } %> - <% if(user_administrator) { %> - <% } %>
InfoReset stats DB+/-
-
- - -
- <% } %> <% } %>
-

-

- -
-

+<% if (overview.statistics_db_node == 'not_running') { %> +

Statistics database could not be contacted. Message rates and queue lengths will not be shown.

+<% } %> <% if (nodes.length == 1 && nodes[0].os_pid != undefined) { %>

Paths

@@ -285,20 +280,23 @@
-

Export definitions

+

Import / export definitions

+
@@ -316,31 +314,6 @@ <% } %> - -
+

Export


+

Import

- - +
+

-
-
- -
-

Import definitions

-
- - - - - - - + + + +
-

-
- -

-
-

- - -

-
<% if (vhosts_interesting) { %> @@ -356,6 +329,21 @@ <% } %>
+

+ + +

+
+

+ + + +

+
diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/partition.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/partition.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/partition.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/partition.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/paths.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/paths.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/paths.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/paths.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/permissions.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/permissions.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/permissions.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/permissions.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs similarity index 91% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs index f93429c..1816f7a 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/policies.ejs @@ -59,7 +59,7 @@ @@ -117,9 +117,7 @@ Max length | Max length bytes
Dead letter exchange | - Dead letter routing key | - Lazy mode | - Master Locator + Dead letter routing key diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/policy.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/policy.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/policy.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/policy.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/publish.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/publish.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/publish.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/publish.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs similarity index 94% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs index 2b7e520..23cad65 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/queue.ejs @@ -18,14 +18,20 @@ Policy <%= fmt_string(queue.policy, '') %> + <% if (queue.owner_pid_details != undefined) { %> + + Exclusive owner + <%= link_conn(queue.owner_pid_details.name) %> + +<% } %> <% if (nodes_interesting) { %> Node <%= fmt_node(queue.node) %> - <% if (!queue.exclusive) { %> + <% if (queue.owner_pid_details == undefined) { %> - Mirrors + Slaves <% var has_unsynced_node = false; @@ -95,7 +101,6 @@ Unacked In memory Persistent - Transient, Paged Out @@ -117,9 +122,6 @@ <%= fmt_num_thousands(queue.messages_persistent) %> - - <%= fmt_num_thousands(queue.messages_paged_out) %> - @@ -141,9 +143,6 @@ <%= fmt_bytes(queue.message_bytes_persistent) %> - - <%= fmt_bytes(queue.message_bytes_paged_out) %> - @@ -290,21 +289,16 @@ <% } %>
-

Delete

+

Delete / purge

-
+
-
-
-
-

Purge

-
-
+ diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs similarity index 94% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs index 9b312fb..f0a78f0 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/queues.ejs @@ -193,7 +193,7 @@ @@ -252,10 +252,7 @@ Max length bytes
Dead letter exchange | Dead letter routing key | - Maximum priority
- Lazy mode - Master locator - + Maximum priority diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/rate-options.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/rate-options.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/rate-options.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/rate-options.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/registry.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/registry.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/registry.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/registry.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/status.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/status.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/status.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/status.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/user.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/user.ejs similarity index 97% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/user.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/user.ejs index 635d408..0201744 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/user.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/user.ejs @@ -63,7 +63,6 @@ [Monitoring] [Policymaker] [Management] - [Impersonator] [None] diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/users.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/users.ejs similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/users.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/users.ejs index e625fed..f0dfc4d 100644 --- a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/users.ejs +++ b/deps/rabbitmq_management/priv/www/js/tmpl/users.ejs @@ -30,7 +30,7 @@ <% } else { %> -

... no users ...

+

... no vhosts ...

<% } %>

@@ -84,7 +84,6 @@ Monitoring | Policymaker | Management | - Impersonator | None diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/vhost.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/vhost.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/vhost.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/vhost.ejs diff --git a/rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs b/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs rename to deps/rabbitmq_management/priv/www/js/tmpl/vhosts.ejs diff --git a/deps/rabbitmq_management/rabbitmq-components.mk b/deps/rabbitmq_management/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_management/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_app.erl b/deps/rabbitmq_management/src/rabbit_mgmt_app.erl new file mode 100644 index 0000000..bde338b --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_app.erl @@ -0,0 +1,114 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_app). + +-behaviour(application). +-export([start/2, stop/1, reset_dispatcher/1]). + +-include("rabbit_mgmt.hrl"). +-include_lib("amqp_client/include/amqp_client.hrl"). + +-define(CONTEXT, rabbit_mgmt). +-define(STATIC_PATH, "priv/www"). + +start(_Type, _StartArgs) -> + {ok, Listener} = application:get_env(rabbitmq_management, listener), + setup_wm_logging(), + register_context(Listener, []), + log_startup(Listener), + rabbit_mgmt_sup_sup:start_link(). + +stop(_State) -> + unregister_context(), + ok. + +%% At the point at which this is invoked we have both newly enabled +%% apps and about-to-disable apps running (so that +%% rabbit_mgmt_reset_handler can look at all of them to find +%% extensions). Therefore we have to explicitly exclude +%% about-to-disable apps from our new dispatcher. +reset_dispatcher(IgnoreApps) -> + unregister_context(), + {ok, Listener} = application:get_env(rabbitmq_management, listener), + register_context(Listener, IgnoreApps). + +register_context(Listener, IgnoreApps) -> + rabbit_web_dispatch:register_context_handler( + ?CONTEXT, Listener, "", make_loop(IgnoreApps), "RabbitMQ Management"). + +unregister_context() -> + rabbit_web_dispatch:unregister_context(?CONTEXT). + +make_loop(IgnoreApps) -> + Dispatch = rabbit_mgmt_dispatcher:build_dispatcher(IgnoreApps), + WMLoop = rabbit_webmachine:makeloop(Dispatch), + LocalPaths = [filename:join(module_path(M), ?STATIC_PATH) || + M <- rabbit_mgmt_dispatcher:modules(IgnoreApps)], + fun(Req) -> respond(Req, LocalPaths, WMLoop) end. + +module_path(Module) -> + {file, Here} = code:is_loaded(Module), + filename:dirname(filename:dirname(Here)). + +respond(Req, LocalPaths, WMLoop) -> + Path = Req:get(path), + Redirect = fun(L) -> {301, [{"Location", L}], ""} end, + case Path of + "/api/" ++ Rest when length(Rest) > 0 -> + WMLoop(Req); + "" -> + Req:respond(Redirect("/")); + "/mgmt/" -> + Req:respond(Redirect("/")); + "/mgmt" -> + Req:respond(Redirect("/")); + "/" ++ Stripped -> + serve_file(Req, Stripped, LocalPaths, Redirect) + end. + +serve_file(Req, Path, [LocalPath], _Redirect) -> + Req:serve_file(Path, LocalPath); +serve_file(Req, Path, [LocalPath | Others], Redirect) -> + Path1 = filename:join([LocalPath, Path]), + case filelib:is_regular(Path1) of + true -> Req:serve_file(Path, LocalPath); + false -> case filelib:is_regular(Path1 ++ "/index.html") of + true -> index(Req, Path, LocalPath, Redirect); + false -> serve_file(Req, Path, Others, Redirect) + end + end. + +index(Req, Path, LocalPath, Redirect) -> + case lists:reverse(Path) of + "" -> Req:serve_file("index.html", LocalPath); + "/" ++ _ -> Req:serve_file(Path ++ "index.html", LocalPath); + _ -> Req:respond(Redirect(Path ++ "/")) + end. + +setup_wm_logging() -> + rabbit_webmachine:setup(), + {ok, LogDir} = application:get_env(rabbitmq_management, http_log_dir), + case LogDir of + none -> ok; + _ -> webmachine_log:add_handler(webmachine_log_handler, [LogDir]) + end. + +log_startup(Listener) -> + rabbit_log:info("Management plugin started. Port: ~w~n", [port(Listener)]). + +port(Listener) -> + proplists:get_value(port, Listener). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_channel_stats_collector.erl b/deps/rabbitmq_management/src/rabbit_mgmt_channel_stats_collector.erl new file mode 100644 index 0000000..6bd222f --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_channel_stats_collector.erl @@ -0,0 +1,125 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_channel_stats_collector). + +-include("rabbit_mgmt.hrl"). +-include("rabbit_mgmt_metrics.hrl"). +-include("rabbit_mgmt_event_collector.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-behaviour(gen_server2). + +-export([start_link/0]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3, handle_pre_hibernate/1]). + +-export([prioritise_cast/3]). + +-import(rabbit_misc, [pget/3]). +-import(rabbit_mgmt_db, [pget/2, id_name/1, id/2, lookup_element/2]). + +prioritise_cast({event, #event{type = channel_stats}}, Len, + #state{max_backlog = MaxBacklog} = _State) + when Len > MaxBacklog -> + drop; +prioritise_cast(_Msg, _Len, _State) -> + 0. + +%% See the comment on rabbit_mgmt_db for the explanation of +%% events and stats. + +%% Although this gen_server could process all types of events through the +%% handle_cast, rabbit_mgmt_db_handler (in the management agent) forwards +%% only the non-prioritiy events channel_stats +%%---------------------------------------------------------------------------- +%% API +%%---------------------------------------------------------------------------- + +start_link() -> + case gen_server2:start_link({global, ?MODULE}, ?MODULE, [], []) of + {ok, Pid} -> register(?MODULE, Pid), %% [1] + {ok, Pid}; + Else -> Else + end. +%% [1] For debugging it's helpful to locally register the name too +%% since that shows up in places global names don't. + +%%---------------------------------------------------------------------------- +%% Internal, gen_server2 callbacks +%%---------------------------------------------------------------------------- + +init([]) -> + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + {ok, RatesMode} = application:get_env(rabbitmq_management, rates_mode), + {ok, MaxBacklog} = application:get_env(rabbitmq_management, + stats_event_max_backlog), + process_flag(priority, high), + rabbit_log:info("Statistics channel stats collector started.~n"), + {ok, reset_lookups( + #state{interval = Interval, + rates_mode = RatesMode, + max_backlog = MaxBacklog}), hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. + +%% Used in rabbit_mgmt_test_db where we need guarantees events have +%% been handled before querying +handle_call({event, Event = #event{reference = none}}, _From, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + reply(ok, State); + +handle_call(_Request, _From, State) -> + reply(not_understood, State). + +%% Only handle events that are real. +handle_cast({event, Event = #event{reference = none}}, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + noreply(State); + +handle_cast({event, Event = #event{reference = Ref}}, + State = #state{event_refresh_ref = Ref}) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + noreply(State); + +handle_cast(_Request, State) -> + noreply(State). + +handle_info(_Info, State) -> + noreply(State). + +terminate(_Arg, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +reply(Reply, NewState) -> {reply, Reply, NewState, hibernate}. +noreply(NewState) -> {noreply, NewState, hibernate}. + +reset_lookups(State) -> + State#state{lookups = [{exchange, fun rabbit_exchange:lookup/1}, + {queue, fun rabbit_amqqueue:lookup/1}]}. + +handle_pre_hibernate(State) -> + %% rabbit_event can end up holding on to some memory after a busy + %% workout, but it's not a gen_server so we can't make it + %% hibernate. The best we can do is forcibly GC it here (if + %% rabbit_mgmt_db is hibernating the odds are rabbit_event is + %% quiescing in some way too). + rpc:multicall( + rabbit_mnesia:cluster_nodes(running), rabbit_mgmt_db_handler, gc, []), + {hibernate, State}. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_cors.erl b/deps/rabbitmq_management/src/rabbit_mgmt_cors.erl new file mode 100644 index 0000000..5226241 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_cors.erl @@ -0,0 +1,88 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +%% Useful documentation about CORS: +%% * https://tools.ietf.org/html/rfc6454 +%% * https://www.w3.org/TR/cors/ +%% * https://staticapps.org/articles/cross-domain-requests-with-cors/ +-module(rabbit_mgmt_cors). + +-export([set_headers/2]). + +%% We don't set access-control-max-age because we currently have +%% no way to know which headers apply to the whole resource. We +%% only know for the next request. +set_headers(ReqData, Module) -> + ReqData1 = case wrq:get_resp_header("vary", ReqData) of + undefined -> wrq:set_resp_header("vary", "origin", ReqData); + VaryValue -> wrq:set_resp_header("vary", VaryValue ++ ", origin", ReqData) + end, + case match_origin(ReqData1) of + false -> + ReqData1; + Origin -> + ReqData2 = case wrq:method(ReqData1) of + 'OPTIONS' -> handle_options(ReqData1, Module); + _ -> ReqData1 + end, + wrq:set_resp_headers([ + {"access-control-allow-origin", Origin}, + {"access-control-allow-credentials", "true"} + ], ReqData2) + end. + +%% Set max-age from configuration (default: 30 minutes). +%% Set allow-methods from what is defined in Module:allowed_methods/2. +%% Set allow-headers to the same as the request (accept all headers). +handle_options(ReqData, Module) -> + MaxAge = application:get_env(rabbitmq_management, cors_max_age, 1800), + {Methods, _, _} = Module:allowed_methods(undefined, undefined), + AllowMethods = string:join([atom_to_list(M) || M <- Methods], ", "), + ReqHeaders = wrq:get_req_header("access-control-request-headers", ReqData), + MaxAgeHd = case MaxAge of + undefined -> []; + _ -> {"access-control-max-age", integer_to_list(MaxAge)} + end, + MaybeAllowHeaders = case ReqHeaders of + undefined -> []; + _ -> [{"access-control-allow-headers", ReqHeaders}] + end, + wrq:set_resp_headers([MaxAgeHd, + {"access-control-allow-methods", AllowMethods} + |MaybeAllowHeaders], ReqData). + +%% If the origin header is missing or "null", we disable CORS. +%% Otherwise, we only enable it if the origin is found in the +%% cors_allow_origins configuration variable, or if "*" is (it +%% allows all origins). +match_origin(ReqData) -> + case wrq:get_req_header("origin", ReqData) of + undefined -> false; + "null" -> false; + Origin -> + AllowedOrigins = application:get_env(rabbitmq_management, + cors_allow_origins, []), + case lists:member(Origin, AllowedOrigins) of + true -> + Origin; + false -> + %% Maybe the configuration explicitly allows "*". + case lists:member("*", AllowedOrigins) of + true -> Origin; + false -> false + end + end + end. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_db.erl b/deps/rabbitmq_management/src/rabbit_mgmt_db.erl new file mode 100644 index 0000000..8692bca --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_db.erl @@ -0,0 +1,702 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_db). + +-include("rabbit_mgmt.hrl"). +-include("rabbit_mgmt_metrics.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-behaviour(gen_server2). + +-export([start_link/0]). +-export([pget/2, id_name/1, id/2, lookup_element/2]). + +-export([augment_exchanges/3, augment_queues/3, + augment_nodes/2, augment_vhosts/2, + get_channel/2, get_connection/2, + get_all_channels/1, get_all_connections/1, + get_all_consumers/0, get_all_consumers/1, + get_overview/2, get_overview/1]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3, handle_pre_hibernate/1, + format_message_queue/2]). + +-import(rabbit_misc, [pget/3]). + +%% The management database listens to events broadcast via the +%% rabbit_event mechanism, and responds to queries from the various +%% rabbit_mgmt_wm_* modules. It handles several kinds of events, and +%% slices and dices them in various ways. +%% +%% There are three types of events coming in: created (when an object +%% is created, containing immutable facts about it), stats (emitted on +%% a timer, with mutable facts about the object), and deleted (just +%% containing the object's ID). In this context "objects" means +%% connections, channels, exchanges, queues, consumers, vhosts and +%% nodes. Note that we do not care about users, permissions, bindings, +%% parameters or policies. +%% +%% Connections and channels are identified by pids. Queues and +%% exchanges are identified by names (which are #resource{}s). VHosts +%% and nodes are identified by names which are binaries. And consumers +%% are identified by {ChPid, QName, CTag}. +%% +%% The management database records the "created" events for +%% connections, channels and consumers, and can thus be authoritative +%% about those objects. For queues, exchanges and nodes we go to +%% Mnesia to find out the immutable details of the objects. +%% +%% For everything other than consumers, the database can then augment +%% these immutable details with stats, as the object changes. (We +%% never emit anything very interesting about consumers). +%% +%% Stats on the inbound side are referred to as coarse- and +%% fine-grained. Fine grained statistics are the message rates +%% maintained by channels and associated with tuples: {publishing +%% channel, exchange}, {publishing channel, exchange, queue} and +%% {queue, consuming channel}. Coarse grained stats are everything +%% else and are associated with only one object, not a tuple. +%% +%% Within the management database though we rearrange things a bit: we +%% refer to basic stats, simple stats and detail stats. +%% +%% Basic stats are those coarse grained stats for which we do not +%% retain a history and do not perform any calculations - +%% e.g. connection.state or channel.prefetch_count. +%% +%% Simple stats are those for which we do history / calculations which +%% are associated with one object *after aggregation* - so these might +%% originate with coarse grained stats - e.g. connection.send_oct or +%% queue.messages_ready. But they might also originate from fine +%% grained stats which have been aggregated - e.g. the message rates +%% for a vhost or queue. +%% +%% Finally, detailed stats are those for which we do history / +%% calculations which are associated with two objects. These +%% have to have originated as fine grained stats, but can still have +%% been aggregated. +%% +%% Created events and basic stats are stored in ETS tables by object. +%% Simple and detailed stats (which only differ depending on how +%% they're keyed) are stored in aggregated stats tables +%% (see rabbit_mgmt_stats.erl and include/rabbit_mgmt_metrics.hrl) +%% +%% Keys from simple and detailed stats are aggregated in several +%% records, stored in different ETS tables. We store a base counter +%% for everything that happened before the samples we have kept, +%% and a series of records which add the timestamp as part of the key. +%% +%% Each ETS aggregated table has a GC process with a timer to periodically +%% aggregate old samples in the base. +%% +%% We also have old_stats to let us calculate instantaneous +%% rates, in order to apportion simple / detailed stats into time +%% slices as they come in. These instantaneous rates are not returned +%% in response to any query, the rates shown in the API are calculated +%% at query time. old_stats contains both coarse and fine +%% entries. Coarse entries are pruned when the corresponding object is +%% deleted, and fine entries are pruned when the emitting channel is +%% closed, and whenever we receive new fine stats from a channel. So +%% it's quite close to being a cache of "the previous stats we +%% received". +%% +%% Overall the object is to do all the aggregation when events come +%% in, and make queries be simple lookups as much as possible. One +%% area where this does not happen is the global overview - which is +%% aggregated from vhost stats at query time since we do not want to +%% reveal anything about other vhosts to unprivileged users. + +%%---------------------------------------------------------------------------- +%% API +%%---------------------------------------------------------------------------- + +start_link() -> + case gen_server2:start_link({global, ?MODULE}, ?MODULE, [], []) of + {ok, Pid} -> register(?MODULE, Pid), %% [1] + {ok, Pid}; + Else -> Else + end. +%% [1] For debugging it's helpful to locally register the name too +%% since that shows up in places global names don't. + +%% R = Ranges, M = Mode +augment_exchanges(Xs, R, M) -> safe_call({augment_exchanges, Xs, R, M}, Xs). +augment_queues(Qs, R, M) -> safe_call({augment_queues, Qs, R, M}, Qs). +augment_vhosts(VHosts, R) -> safe_call({augment_vhosts, VHosts, R}, VHosts). +augment_nodes(Nodes, R) -> safe_call({augment_nodes, Nodes, R}, Nodes). + +get_channel(Name, R) -> safe_call({get_channel, Name, R}, not_found). +get_connection(Name, R) -> safe_call({get_connection, Name, R}, not_found). + +get_all_channels(R) -> safe_call({get_all_channels, R}). +get_all_connections(R) -> safe_call({get_all_connections, R}). + +get_all_consumers() -> safe_call({get_all_consumers, all}). +get_all_consumers(V) -> safe_call({get_all_consumers, V}). + +get_overview(User, R) -> safe_call({get_overview, User, R}). +get_overview(R) -> safe_call({get_overview, all, R}). + +safe_call(Term) -> safe_call(Term, []). +safe_call(Term, Default) -> safe_call(Term, Default, 1). + +%% See rabbit_mgmt_sup_sup for a discussion of the retry logic. +safe_call(Term, Default, Retries) -> + rabbit_misc:with_exit_handler( + fun () -> + case Retries of + 0 -> Default; + _ -> rabbit_mgmt_sup_sup:start_child(), + safe_call(Term, Default, Retries - 1) + end + end, + fun () -> gen_server2:call({global, ?MODULE}, Term, infinity) end). + +%%---------------------------------------------------------------------------- +%% Internal, gen_server2 callbacks +%%---------------------------------------------------------------------------- + +-record(state, {interval}). + +init([]) -> + %% When Rabbit is overloaded, it's usually especially important + %% that the management plugin work. + process_flag(priority, high), + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + rabbit_log:info("Statistics database started.~n"), + {ok, #state{interval = Interval}, hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. + +handle_call({augment_exchanges, Xs, Ranges, basic}, _From, + #state{interval = Interval} = State) -> + reply(list_exchange_stats(Ranges, Xs, Interval), State); + +handle_call({augment_exchanges, Xs, Ranges, full}, _From, + #state{interval = Interval} = State) -> + reply(detail_exchange_stats(Ranges, Xs, Interval), State); + +handle_call({augment_queues, Qs, Ranges, basic}, _From, + #state{interval = Interval} = State) -> + reply(list_queue_stats(Ranges, Qs, Interval), State); + +handle_call({augment_queues, Qs, Ranges, full}, _From, + #state{interval = Interval} = State) -> + reply(detail_queue_stats(Ranges, Qs, Interval), State); + +handle_call({augment_vhosts, VHosts, Ranges}, _From, + #state{interval = Interval} = State) -> + reply(vhost_stats(Ranges, VHosts, Interval), State); + +handle_call({augment_nodes, Nodes, Ranges}, _From, + #state{interval = Interval} = State) -> + {reply, node_stats(Ranges, Nodes, Interval), State}; + +handle_call({get_channel, Name, Ranges}, _From, + #state{interval = Interval} = State) -> + case created_event(Name, channel_stats) of + not_found -> reply(not_found, State); + Ch -> [Result] = detail_channel_stats(Ranges, [Ch], Interval), + reply(Result, State) + end; + +handle_call({get_connection, Name, Ranges}, _From, + #state{interval = Interval} = State) -> + case created_event(Name, connection_stats) of + not_found -> reply(not_found, State); + Conn -> [Result] = connection_stats(Ranges, [Conn], Interval), + reply(Result, State) + end; + +handle_call({get_all_channels, Ranges}, _From, + #state{interval = Interval} = State) -> + Chans = created_events(channel_stats), + reply(list_channel_stats(Ranges, Chans, Interval), State); + +handle_call({get_all_connections, Ranges}, _From, + #state{interval = Interval} = State) -> + Conns = created_events(connection_stats), + reply(connection_stats(Ranges, Conns, Interval), State); + +handle_call({get_all_consumers, VHost}, _From, State) -> + {reply, [augment_msg_stats(augment_consumer(Obj)) || + Obj <- consumers_by_queue_and_vhost(VHost)], State}; + +handle_call({get_overview, User, Ranges}, _From, + #state{interval = Interval} = State) -> + VHosts = case User of + all -> rabbit_vhost:list(); + _ -> rabbit_mgmt_util:list_visible_vhosts(User) + end, + %% TODO: there's no reason we can't do an overview of send_oct and + %% recv_oct now! + MessageStats = [overview_sum(Type, VHosts) || + Type <- [fine_stats, deliver_get, queue_msg_rates]], + QueueStats = [overview_sum(queue_msg_counts, VHosts)], + F = case User of + all -> fun (L) -> length(L) end; + _ -> fun (L) -> length(rabbit_mgmt_util:filter_user(L, User)) end + end, + %% Filtering out the user's consumers would be rather expensive so let's + %% just not show it + Consumers = case User of + all -> [{consumers, ets:info(consumers_by_queue, size)}]; + _ -> [] + end, + ObjectTotals = Consumers ++ + [{queues, length([Q || V <- VHosts, + Q <- rabbit_amqqueue:list(V)])}, + {exchanges, length([X || V <- VHosts, + X <- rabbit_exchange:list(V)])}, + {connections, F(created_events(connection_stats))}, + {channels, F(created_events(channel_stats))}], + FormatMessage = format_samples(Ranges, MessageStats, Interval), + FormatQueue = format_samples(Ranges, QueueStats, Interval), + [rabbit_mgmt_stats:free(S) || {S, _, _} <- MessageStats], + [rabbit_mgmt_stats:free(S) || {S, _, _} <- QueueStats], + reply([{message_stats, FormatMessage}, + {queue_totals, FormatQueue}, + {object_totals, ObjectTotals}, + {statistics_db_event_queue, event_queue()}], + State); + +handle_call(_Request, _From, State) -> + reply(not_understood, State). + +handle_cast(_Request, State) -> + noreply(State). + +handle_info(_Info, State) -> + noreply(State). + +terminate(_Arg, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +reply(Reply, NewState) -> {reply, Reply, NewState, hibernate}. +noreply(NewState) -> {noreply, NewState, hibernate}. + +handle_pre_hibernate(State) -> + %% rabbit_event can end up holding on to some memory after a busy + %% workout, but it's not a gen_server so we can't make it + %% hibernate. The best we can do is forcibly GC it here (if + %% rabbit_mgmt_db is hibernating the odds are rabbit_event is + %% quiescing in some way too). + rpc:multicall( + rabbit_mnesia:cluster_nodes(running), rabbit_mgmt_db_handler, gc, []), + {hibernate, State}. + +format_message_queue(Opt, MQ) -> rabbit_misc:format_message_queue(Opt, MQ). + +%%---------------------------------------------------------------------------- +%% Internal, utilities +%%---------------------------------------------------------------------------- + +pget(Key, List) -> pget(Key, List, unknown). + +%% id_name() and id() are for use when handling events, id_lookup() +%% for when augmenting. The difference is that when handling events a +%% queue name will be a resource, but when augmenting we will be +%% passed a queue proplist that will already have been formatted - +%% i.e. it will have name and vhost keys. +id_name(node_stats) -> name; +id_name(node_node_stats) -> route; +id_name(vhost_stats) -> name; +id_name(queue_stats) -> name; +id_name(exchange_stats) -> name; +id_name(channel_stats) -> pid; +id_name(connection_stats) -> pid. + +id(Type, List) -> pget(id_name(Type), List). + +id_lookup(queue_stats, List) -> + rabbit_misc:r(pget(vhost, List), queue, pget(name, List)); +id_lookup(exchange_stats, List) -> + rabbit_misc:r(pget(vhost, List), exchange, pget(name, List)); +id_lookup(Type, List) -> + id(Type, List). + +lookup_element(Table, Key) -> lookup_element(Table, Key, 2). + +lookup_element(Table, Key, Pos) -> + try ets:lookup_element(Table, Key, Pos) + catch error:badarg -> [] + end. + +%%---------------------------------------------------------------------------- +%% Internal, querying side +%%---------------------------------------------------------------------------- + +-define(QUEUE_DETAILS, + {queue_stats, [{incoming, queue_exchange_stats, fun first/1}, + {deliveries, channel_queue_stats, fun second/1}]}). + +-define(EXCHANGE_DETAILS, + {exchange_stats, [{incoming, channel_exchange_stats, fun second/1}, + {outgoing, queue_exchange_stats, fun second/1}]}). + +-define(CHANNEL_DETAILS, + {channel_stats, [{publishes, channel_exchange_stats, fun first/1}, + {deliveries, channel_queue_stats, fun first/1}]}). + +-define(NODE_DETAILS, + {node_stats, [{cluster_links, node_node_stats, fun first/1}]}). + +first(Id) -> + {Id, '_'}. +second(Id) -> + {'_', Id}. + +list_queue_stats(Ranges, Objs, Interval) -> + adjust_hibernated_memory_use( + merge_queue_stats(Objs, queue_funs(Ranges, Interval))). + +detail_queue_stats(Ranges, Objs, Interval) -> + adjust_hibernated_memory_use( + merge_queue_stats(Objs, + [consumer_details_fun( + fun (Props) -> id_lookup(queue_stats, Props) end, + consumers_by_queue), + detail_stats_fun(Ranges, ?QUEUE_DETAILS, Interval) + | queue_funs(Ranges, Interval)])). + +queue_funs(Ranges, Interval) -> + [basic_stats_fun(queue_stats), + simple_stats_fun(Ranges, queue_stats, Interval), + augment_queue_msg_stats_fun()]. + +list_exchange_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [simple_stats_fun(Ranges, exchange_stats, Interval), + augment_msg_stats_fun()]). + +detail_exchange_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [simple_stats_fun(Ranges, exchange_stats, Interval), + detail_stats_fun(Ranges, ?EXCHANGE_DETAILS, Interval), + augment_msg_stats_fun()]). + +connection_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [basic_stats_fun(connection_stats), + simple_stats_fun(Ranges, connection_stats, Interval), + augment_msg_stats_fun()]). + +list_channel_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [basic_stats_fun(channel_stats), + simple_stats_fun(Ranges, channel_stats, Interval), + augment_msg_stats_fun()]). + +detail_channel_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [basic_stats_fun(channel_stats), + simple_stats_fun(Ranges, channel_stats, Interval), + consumer_details_fun( + fun (Props) -> pget(pid, Props) end, + consumers_by_channel), + detail_stats_fun(Ranges, ?CHANNEL_DETAILS, Interval), + augment_msg_stats_fun()]). + +vhost_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [simple_stats_fun(Ranges, vhost_stats, Interval)]). + +node_stats(Ranges, Objs, Interval) -> + merge_stats(Objs, [basic_stats_fun(node_stats), + simple_stats_fun(Ranges, node_stats, Interval), + detail_and_basic_stats_fun( + node_node_stats, Ranges, ?NODE_DETAILS, Interval)]). + +merge_stats(Objs, Funs) -> + %% Don't pass the props to the Fun in combine, as it contains the results + %% from previous funs and: + %% * augment_msg_stats_fun() only needs the original object. Otherwise, + %% must fold over a very longs list + %% * All other funs only require the Type that is in the original Obj + [combine_all_funs(Funs, Obj, Obj) || Obj <- Objs]. + +combine_all_funs([Fun | Funs], Obj, Props) -> + combine_all_funs(Funs, Obj, combine(Fun(Obj), Props)); +combine_all_funs([], _Obj, Props) -> + Props. + +merge_queue_stats(Objs, Funs) -> + %% Don't pass the props to the Fun in combine, as it contains the results + %% from previous funs and: + %% * augment_msg_stats_fun() only needs the original object. Otherwise, + %% must fold over a very longs list + %% * All other funs only require the Type that is in the original Obj + [begin + Pid = pget(pid, Obj), + {Pid, combine_all_funs(Funs, Obj, rabbit_mgmt_format:strip_queue_pids(Obj))} + end || Obj <- Objs]. + +combine(New, Old) -> + case pget(state, Old) of + unknown -> New ++ Old; + live -> New ++ lists:keydelete(state, 1, Old); + _ -> lists:keydelete(state, 1, New) ++ Old + end. + +%% i.e. the non-calculated stats +basic_stats_fun(Type) -> + fun (Props) -> + Id = id_lookup(Type, Props), + lookup_element(Type, {Id, stats}) + end. + +%% i.e. coarse stats, and fine stats aggregated up to a single number per thing +simple_stats_fun(Ranges, Type, Interval) -> + {Msg, Other} = read_simple_stats(Type), + fun (Props) -> + Id = id_lookup(Type, Props), + OtherStats = format_samples(Ranges, {Id, Other}, Interval), + case format_samples(Ranges, {Id, Msg}, Interval) of + [] -> + OtherStats; + MsgStats -> + [{message_stats, MsgStats} | OtherStats] + end + end. + +%% i.e. fine stats that are broken out per sub-thing +detail_stats_fun(Ranges, {IdType, FineSpecs}, Interval) -> + fun (Props) -> + Id = id_lookup(IdType, Props), + [detail_stats(Ranges, Name, AggregatedStatsType, IdFun(Id), Interval) + || {Name, AggregatedStatsType, IdFun} <- FineSpecs] + end. + +%% This does not quite do the same as detail_stats_fun + +%% basic_stats_fun; the basic part here assumes compound keys (like +%% detail stats) but non-calculated (like basic stats). Currently the +%% only user of that is node-node stats. +%% +%% We also assume that FineSpecs is single length here (at [1]). +detail_and_basic_stats_fun(Type, Ranges, {IdType, FineSpecs}, Interval) -> + F = detail_stats_fun(Ranges, {IdType, FineSpecs}, Interval), + fun (Props) -> + Id = id_lookup(IdType, Props), + BasicStats = ets:select(Type, [{{{{'$1', '$2'}, '$3'}, '$4', '_'}, + [{'==', '$1', Id}, + {'==', '$3', stats}], + [{{'$2', '$4'}}]}]), + [{K, Items}] = F(Props), %% [1] + Items2 = [case lists:keyfind(id_lookup(IdType, Item), 1, BasicStats) of + false -> Item; + {_, BS} -> BS ++ Item + end || Item <- Items], + [{K, Items2}] + end. + +read_simple_stats(EventType) -> + lists:partition( + fun({_, Type}) -> + lists:member(Type, [fine_stats, deliver_get, queue_msg_rates]) + end, rabbit_mgmt_stats_tables:aggr_tables(EventType)). + +read_detail_stats(EventType, Id) -> + Tables = rabbit_mgmt_stats_tables:aggr_tables(EventType), + Keys = [{Table, Type, Key} || {Table, Type} <- Tables, + Key <- rabbit_mgmt_stats:get_keys(Table, Id)], + lists:foldl( + fun ({_Table, _Type, Id0} = Entry, L) -> + NewId = revert(Id, Id0), + case lists:keyfind(NewId, 1, L) of + false -> + [{NewId, [Entry]} | L]; + {NewId, KVs} -> + lists:keyreplace(NewId, 1, L, {NewId, [Entry | KVs]}) + end + end, [], Keys). + +revert({'_', _}, {Id, _}) -> + Id; +revert({_, '_'}, {_, Id}) -> + Id. + +detail_stats(Ranges, Name, AggregatedStatsType, Id, Interval) -> + {Name, + [[{stats, format_samples(Ranges, KVs, Interval)} | format_detail_id(G)] + || {G, KVs} <- read_detail_stats(AggregatedStatsType, Id)]}. + +format_detail_id(ChPid) when is_pid(ChPid) -> + augment_msg_stats([{channel, ChPid}]); +format_detail_id(#resource{name = Name, virtual_host = Vhost, kind = Kind}) -> + [{Kind, [{name, Name}, {vhost, Vhost}]}]; +format_detail_id(Node) when is_atom(Node) -> + [{name, Node}]. + +format_samples(Ranges, {Id, ManyStats}, Interval) -> + lists:append(foldl_stats_format(ManyStats, Id, Ranges, Interval, [])); +format_samples(Ranges, ManyStats, Interval) -> + lists:append(foldl_stats_format(ManyStats, Ranges, Interval, [])). + +foldl_stats_format([{Table, Record} | T], Id, Ranges, Interval, Acc) -> + foldl_stats_format(T, Id, Ranges, Interval, + stats_format(Table, Id, Record, Ranges, Interval, Acc)); +foldl_stats_format([], _Id, _Ranges, _Interval, Acc) -> + Acc. + +foldl_stats_format([{Table, Record, Id} | T], Ranges, Interval, Acc) -> + foldl_stats_format(T, Ranges, Interval, + stats_format(Table, Id, Record, Ranges, Interval, Acc)); +foldl_stats_format([], _Ranges, _Interval, Acc) -> + Acc. + +stats_format(Table, Id, Record, Ranges, Interval, Acc) -> + case rabbit_mgmt_stats:is_blank(Table, Id, Record) of + true -> + Acc; + false -> + [rabbit_mgmt_stats:format(pick_range(Record, Ranges), + Table, Id, Interval, Record) | Acc] + end. + +pick_range(queue_msg_counts, {RangeL, _RangeM, _RangeD, _RangeN}) -> + RangeL; +pick_range(K, {_RangeL, RangeM, _RangeD, _RangeN}) when K == fine_stats; + K == deliver_get; + K == queue_msg_rates -> + RangeM; +pick_range(K, {_RangeL, _RangeM, RangeD, _RangeN}) when K == coarse_conn_stats; + K == process_stats -> + RangeD; +pick_range(K, {_RangeL, _RangeM, _RangeD, RangeN}) + when K == coarse_node_stats; + K == coarse_node_node_stats -> + RangeN. + +%% We do this when retrieving the queue record rather than when +%% storing it since the memory use will drop *after* we find out about +%% hibernation, so to do it when we receive a queue stats event would +%% be fiddly and racy. This should be quite cheap though. +adjust_hibernated_memory_use(Qs) -> + Pids = [Pid || {Pid, Q} <- Qs, pget(idle_since, Q, not_idle) =/= not_idle], + %% We use delegate here not for ordering reasons but because we + %% want to get the right amount of parallelism and minimise + %% cross-cluster communication. + {Mem, _BadNodes} = delegate:invoke(Pids, {erlang, process_info, [memory]}), + MemDict = dict:from_list([{P, M} || {P, M = {memory, _}} <- Mem]), + [case dict:find(Pid, MemDict) of + error -> Q; + {ok, Memory} -> [Memory|proplists:delete(memory, Q)] + end || {Pid, Q} <- Qs]. + +created_event(Name, Type) -> + case ets:select(Type, [{{{'_', '$1'}, '$2', '$3'}, [{'==', 'create', '$1'}, + {'==', Name, '$3'}], + ['$2']}]) of + [] -> not_found; + [Elem] -> Elem + end. + +created_events(Type) -> + ets:select(Type, [{{{'_', '$1'}, '$2', '_'}, [{'==', 'create', '$1'}], + ['$2']}]). + +consumers_by_queue_and_vhost(VHost) -> + ets:select(consumers_by_queue, + [{{{#resource{virtual_host = '$1', _ = '_'}, '_', '_'}, '$2'}, + [{'orelse', {'==', 'all', VHost}, {'==', VHost, '$1'}}], + ['$2']}]). + +consumer_details_fun(KeyFun, TableName) -> + fun ([]) -> []; + (Props) -> Pattern = {KeyFun(Props), '_', '_'}, + [{consumer_details, + [augment_msg_stats(augment_consumer(Obj)) + || Obj <- lists:append( + ets:match(TableName, {Pattern, '$1'}))]}] + end. + +augment_consumer(Obj) -> + [{queue, rabbit_mgmt_format:resource(pget(queue, Obj))} | + lists:keydelete(queue, 1, Obj)]. + +%%---------------------------------------------------------------------------- +%% Internal, query-time summing for overview +%%---------------------------------------------------------------------------- + +overview_sum(Type, VHosts) -> + Stats = [{rabbit_mgmt_stats_tables:aggr_table(vhost_stats, Type), VHost} + || VHost <- VHosts], + {rabbit_mgmt_stats:sum(Stats), Type, all}. + +%%---------------------------------------------------------------------------- +%% Internal, query-time augmentation +%%---------------------------------------------------------------------------- + +augment_msg_stats(Props) -> + rabbit_mgmt_format:strip_pids( + (augment_msg_stats_fun())(Props) ++ Props). + +augment_msg_stats_fun() -> + fun(Props) -> + augment_details(Props, []) + end. + +augment_details([{_, none} | T], Acc) -> + augment_details(T, Acc); +augment_details([{_, unknown} | T], Acc) -> + augment_details(T, Acc); +augment_details([{connection, Value} | T], Acc) -> + augment_details(T, [{connection_details, augment_connection_pid(Value)} | Acc]); +augment_details([{channel, Value} | T], Acc) -> + augment_details(T, [{channel_details, augment_channel_pid(Value)} | Acc]); +augment_details([{owner_pid, Value} | T], Acc) -> + augment_details(T, [{owner_pid_details, augment_connection_pid(Value)} | Acc]); +augment_details([_ | T], Acc) -> + augment_details(T, Acc); +augment_details([], Acc) -> + Acc. + +augment_queue_msg_stats_fun() -> + fun(Props) -> + case lists:keyfind(owner_pid, 1, Props) of + {owner_pid, Value} when is_pid(Value) -> + [{owner_pid_details, augment_connection_pid(Value)}]; + _ -> + [] + end + end. + +augment_channel_pid(Pid) -> + Ch = lookup_element(channel_stats, {Pid, create}), + Conn = lookup_element(connection_stats, + {pget(connection, Ch), create}), + [{name, pget(name, Ch)}, + {number, pget(number, Ch)}, + {user, pget(user, Ch)}, + {connection_name, pget(name, Conn)}, + {peer_port, pget(peer_port, Conn)}, + {peer_host, pget(peer_host, Conn)}]. + +augment_connection_pid(Pid) -> + Conn = lookup_element(connection_stats, {Pid, create}), + [{name, pget(name, Conn)}, + {peer_port, pget(peer_port, Conn)}, + {peer_host, pget(peer_host, Conn)}]. + +event_queue() -> + {message_queue_len, Q0} = + erlang:process_info(whereis(rabbit_mgmt_event_collector), + message_queue_len), + {message_queue_len, Q1} = + erlang:process_info(whereis(rabbit_mgmt_queue_stats_collector), + message_queue_len), + {message_queue_len, Q2} = + erlang:process_info(whereis(rabbit_mgmt_channel_stats_collector), + message_queue_len), + Q0 + Q1 + Q2. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl b/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl new file mode 100644 index 0000000..53b05ae --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_dispatcher.erl @@ -0,0 +1,101 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_dispatcher). + +-export([modules/1, build_dispatcher/1]). + +-behaviour(rabbit_mgmt_extension). +-export([dispatcher/0, web_ui/0]). + +build_dispatcher(Ignore) -> + [{["api" | Path], Mod, Args} || + {Path, Mod, Args} <- + lists:append([Module:dispatcher() || Module <- modules(Ignore)])]. + +modules(IgnoreApps) -> + [Module || {App, Module, Behaviours} <- + rabbit_misc:all_module_attributes(behaviour), + not lists:member(App, IgnoreApps), + lists:member(rabbit_mgmt_extension, Behaviours)]. + +%%---------------------------------------------------------------------------- + +web_ui() -> [{javascript, <<"dispatcher.js">>}]. + +dispatcher() -> + [{["overview"], rabbit_mgmt_wm_overview, []}, + {["cluster-name"], rabbit_mgmt_wm_cluster_name, []}, + {["nodes"], rabbit_mgmt_wm_nodes, []}, + {["nodes", node], rabbit_mgmt_wm_node, []}, + {["nodes", node, "memory"], rabbit_mgmt_wm_node_memory, [absolute]}, + {["nodes", node, "memory", "relative"], rabbit_mgmt_wm_node_memory, [relative]}, + {["nodes", node, "memory", "ets"], rabbit_mgmt_wm_node_memory_ets, [absolute]}, + {["nodes", node, "memory", "ets", "relative"], rabbit_mgmt_wm_node_memory_ets, [relative]}, + {["nodes", node, "memory", "ets", filter], rabbit_mgmt_wm_node_memory_ets, [absolute]}, + {["nodes", node, "memory", "ets", filter, "relative"], rabbit_mgmt_wm_node_memory_ets, [relative]}, + {["extensions"], rabbit_mgmt_wm_extensions, []}, + {["all-configuration"], rabbit_mgmt_wm_definitions, []}, %% This was the old name, let's not break things gratuitously. + {["definitions"], rabbit_mgmt_wm_definitions, []}, + {["definitions", vhost], rabbit_mgmt_wm_definitions, []}, + {["parameters"], rabbit_mgmt_wm_parameters, []}, + {["parameters", component], rabbit_mgmt_wm_parameters, []}, + {["parameters", component, vhost], rabbit_mgmt_wm_parameters, []}, + {["parameters", component, vhost, name], rabbit_mgmt_wm_parameter, []}, + {["policies"], rabbit_mgmt_wm_policies, []}, + {["policies", vhost], rabbit_mgmt_wm_policies, []}, + {["policies", vhost, name], rabbit_mgmt_wm_policy, []}, + {["connections"], rabbit_mgmt_wm_connections, []}, + {["connections", connection], rabbit_mgmt_wm_connection, []}, + {["connections", connection, "channels"], rabbit_mgmt_wm_connection_channels, []}, + {["channels"], rabbit_mgmt_wm_channels, []}, + {["channels", channel], rabbit_mgmt_wm_channel, []}, + {["consumers"], rabbit_mgmt_wm_consumers, []}, + {["consumers", vhost], rabbit_mgmt_wm_consumers, []}, + {["exchanges"], rabbit_mgmt_wm_exchanges, []}, + {["exchanges", vhost], rabbit_mgmt_wm_exchanges, []}, + {["exchanges", vhost, exchange], rabbit_mgmt_wm_exchange, []}, + {["exchanges", vhost, exchange, "publish"], rabbit_mgmt_wm_exchange_publish, []}, + {["exchanges", vhost, exchange, "bindings", "source"], rabbit_mgmt_wm_bindings, [exchange_source]}, + {["exchanges", vhost, exchange, "bindings", "destination"], rabbit_mgmt_wm_bindings, [exchange_destination]}, + {["queues"], rabbit_mgmt_wm_queues, []}, + {["queues", vhost], rabbit_mgmt_wm_queues, []}, + {["queues", vhost, queue], rabbit_mgmt_wm_queue, []}, + {["queues", vhost, destination, "bindings"], rabbit_mgmt_wm_bindings, [queue]}, + {["queues", vhost, queue, "contents"], rabbit_mgmt_wm_queue_purge, []}, + {["queues", vhost, queue, "get"], rabbit_mgmt_wm_queue_get, []}, + {["queues", vhost, queue, "actions"], rabbit_mgmt_wm_queue_actions, []}, + {["bindings"], rabbit_mgmt_wm_bindings, [all]}, + {["bindings", vhost], rabbit_mgmt_wm_bindings, [all]}, + {["bindings", vhost, "e", source, dtype, destination], rabbit_mgmt_wm_bindings, [source_destination]}, + {["bindings", vhost, "e", source, dtype, destination, props], rabbit_mgmt_wm_binding, []}, + {["vhosts"], rabbit_mgmt_wm_vhosts, []}, + {["vhosts", vhost], rabbit_mgmt_wm_vhost, []}, + {["vhosts", vhost, "permissions"], rabbit_mgmt_wm_permissions_vhost, []}, + %% /connections/:connection is already taken, we cannot use our standard scheme here + {["vhosts", vhost, "connections"], rabbit_mgmt_wm_connections_vhost, []}, + %% /channels/:channel is already taken, we cannot use our standard scheme here + {["vhosts", vhost, "channels"], rabbit_mgmt_wm_channels_vhost, []}, + {["users"], rabbit_mgmt_wm_users, []}, + {["users", user], rabbit_mgmt_wm_user, []}, + {["users", user, "permissions"], rabbit_mgmt_wm_permissions_user, []}, + {["whoami"], rabbit_mgmt_wm_whoami, []}, + {["permissions"], rabbit_mgmt_wm_permissions, []}, + {["permissions", vhost, user], rabbit_mgmt_wm_permission, []}, + {["aliveness-test", vhost], rabbit_mgmt_wm_aliveness_test, []}, + {["healthchecks", "node"], rabbit_mgmt_wm_healthchecks, []}, + {["healthchecks", "node", node], rabbit_mgmt_wm_healthchecks, []} + ]. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_event_collector.erl b/deps/rabbitmq_management/src/rabbit_mgmt_event_collector.erl new file mode 100644 index 0000000..a798453 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_event_collector.erl @@ -0,0 +1,165 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_event_collector). + +-include("rabbit_mgmt.hrl"). +-include("rabbit_mgmt_metrics.hrl"). +-include("rabbit_mgmt_event_collector.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-behaviour(gen_server2). + +-export([start_link/0]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3, handle_pre_hibernate/1]). + +%% For testing +-export([override_lookups/1, reset_lookups/0]). + +-import(rabbit_mgmt_db, [pget/2]). + +%% See the comment on rabbit_mgmt_db for the explanation of +%% events and stats. + +%% Although this gen_server could process all types of events through the +%% handle_cast, rabbit_mgmt_db_handler (in the management agent) forwards +%% the non-prioritiy events channel_stats and queue_stats to their own gen_servers + +%%---------------------------------------------------------------------------- +%% API +%%---------------------------------------------------------------------------- + +start_link() -> + Ref = make_ref(), + case gen_server2:start_link({global, ?MODULE}, ?MODULE, [Ref], []) of + {ok, Pid} -> register(?MODULE, Pid), %% [1] + rabbit:force_event_refresh(Ref), + {ok, Pid}; + Else -> Else + end. +%% [1] For debugging it's helpful to locally register the name too +%% since that shows up in places global names don't. + +override_lookups(Lookups) -> + gen_server2:call({global, ?MODULE}, {override_lookups, Lookups}, infinity). +reset_lookups() -> + gen_server2:call({global, ?MODULE}, reset_lookups, infinity). + +%%---------------------------------------------------------------------------- +%% Internal, gen_server2 callbacks +%%---------------------------------------------------------------------------- + +init([Ref]) -> + %% When Rabbit is overloaded, it's usually especially important + %% that the management plugin work. + process_flag(priority, high), + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + {ok, RatesMode} = application:get_env(rabbitmq_management, rates_mode), + rabbit_node_monitor:subscribe(self()), + rabbit_log:info("Statistics event collector started.~n"), + ?TABLES = [ets:new(Key, [public, set, named_table]) || Key <- ?TABLES], + %% Index for cleaning up stats of abnormally terminated processes. + [ets:new(rabbit_mgmt_stats_tables:key_index(Table), + [ordered_set, public, named_table]) || Table <- ?PROC_STATS_TABLES], + %% Index for the deleting of fine stats, reduces the number of reductions + %% to 1/8 under heavy load. + ets:new(old_stats_fine_index, [bag, public, named_table]), + ?AGGR_TABLES = [rabbit_mgmt_stats:blank(Name) || Name <- ?AGGR_TABLES], + {ok, reset_lookups( + #state{interval = Interval, + event_refresh_ref = Ref, + rates_mode = RatesMode}), hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. + +%% Used in rabbit_mgmt_test_db where we need guarantees events have +%% been handled before querying +handle_call({event, Event = #event{reference = none}}, _From, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + reply(ok, State); + +handle_call({override_lookups, Lookups}, _From, State) -> + reply(ok, State#state{lookups = Lookups}); + +handle_call(reset_lookups, _From, State) -> + reply(ok, reset_lookups(State)); + +handle_call(_Request, _From, State) -> + reply(not_understood, State). + +%% Only handle events that are real, or pertain to a force-refresh +%% that we instigated. +handle_cast({event, Event = #event{reference = none}}, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + noreply(State); + +handle_cast({event, Event = #event{reference = Ref}}, + State = #state{event_refresh_ref = Ref}) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + noreply(State); + +handle_cast(_Request, State) -> + noreply(State). + +handle_info({node_down, Node}, State) -> + Conns = created_events(connection_stats), + Chs = created_events(channel_stats), + delete_all_from_node(connection_closed, Node, Conns, State), + delete_all_from_node(channel_closed, Node, Chs, State), + noreply(State); + +handle_info(_Info, State) -> + noreply(State). + +terminate(_Arg, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +reply(Reply, NewState) -> {reply, Reply, NewState, hibernate}. +noreply(NewState) -> {noreply, NewState, hibernate}. + +reset_lookups(State) -> + State#state{lookups = [{exchange, fun rabbit_exchange:lookup/1}, + {queue, fun rabbit_amqqueue:lookup/1}]}. + +handle_pre_hibernate(State) -> + %% rabbit_event can end up holding on to some memory after a busy + %% workout, but it's not a gen_server so we can't make it + %% hibernate. The best we can do is forcibly GC it here (if + %% rabbit_mgmt_db is hibernating the odds are rabbit_event is + %% quiescing in some way too). + rpc:multicall( + rabbit_mnesia:cluster_nodes(running), rabbit_mgmt_db_handler, gc, []), + {hibernate, State}. + +delete_all_from_node(Type, Node, [Item | Items], State) -> + Pid = pget(pid, Item), + case node(Pid) of + Node -> + rabbit_mgmt_event_collector_utils:handle_event( + #event{type = Type, props = [{pid, Pid}]}, State); + _ -> ok + end, + delete_all_from_node(Type, Node, Items, State); +delete_all_from_node(_Type, _Node, [], _State) -> + ok. + +created_events(Table) -> + ets:select(Table, [{{{'_', '$1'}, '$2', '_'}, [{'==', 'create', '$1'}], + ['$2']}]). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_event_collector_utils.erl b/deps/rabbitmq_management/src/rabbit_mgmt_event_collector_utils.erl new file mode 100644 index 0000000..d7d2ee1 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_event_collector_utils.erl @@ -0,0 +1,551 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_event_collector_utils). + +-include("rabbit_mgmt_metrics.hrl"). +-include("rabbit_mgmt_event_collector.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-export([handle_event/2]). + +-import(rabbit_misc, [pget/3]). +-import(rabbit_mgmt_db, [pget/2, id_name/1, id/2, lookup_element/2]). + +%%---------------------------------------------------------------------------- +%% External functions +%%---------------------------------------------------------------------------- + +%%------------------------------------------------------------------------------ %% @doc Handles events from any collector. +%% +%% All the gen_server of the collectors have the same internal state record, +%% which contains the interval, lookups and rate_mode required +%% by this function. Apart from the lookups that can be modified by the +%% tests, the rest of the state doesn't change after startup. +%% +%% Ideally, the gen_server should pass only the required parameters and not the +%% full state. However, this simplified the refactor and avoided changing all +%% internal functions. +%% +%% @end +%%------------------------------------------------------------------------------ +-spec handle_event(#event{}, #state{}) -> ok. +handle_event(#event{type = queue_stats, props = Stats, timestamp = Timestamp}, + State) -> + handle_stats(queue_stats, Stats, Timestamp, + {fun rabbit_mgmt_format:format_queue_stats/1, false}, + ?QUEUE_MSG_COUNTS, ?QUEUE_MSG_RATES ++ ?PROCESS_STATS, State); + +handle_event(Event = #event{type = queue_deleted, + props = [{name, Name}], + timestamp = Timestamp}, + State) -> + delete_consumers(Name, consumers_by_queue, consumers_by_channel), + %% This is fiddly. Unlike for connections and channels, we need to + %% decrease any amalgamated coarse stats for [messages, + %% messages_ready, messages_unacknowledged] for this queue - since + %% the queue's deletion means we have really got rid of messages! + Id = {coarse, {queue_stats, Name}}, + %% This ceil must correspond to the ceil in append_samples/5 + TS = ceil(Timestamp, State), + OldStats = lookup_element(old_stats, Id), + record_sample_list(Id, OldStats, TS, State, ?QUEUE_MSG_COUNTS), + delete_samples(channel_queue_stats, {'_', Name}), + delete_samples(queue_exchange_stats, {Name, '_'}), + delete_samples(queue_stats, Name), + handle_deleted(queue_stats, Event); + +handle_event(Event = #event{type = exchange_deleted, + props = [{name, Name}]}, _State) -> + delete_samples(channel_exchange_stats, {'_', Name}), + delete_samples(queue_exchange_stats, {'_', Name}), + delete_samples(exchange_stats, Name), + handle_deleted(exchange_stats, Event); + +handle_event(#event{type = vhost_deleted, + props = [{name, Name}]}, _State) -> + delete_samples(vhost_stats, Name); + +handle_event(#event{type = connection_created, props = Stats}, _State) -> + handle_created( + connection_stats, Stats, + {fun rabbit_mgmt_format:format_connection_created/1, true}); + +handle_event(#event{type = connection_stats, props = Stats, + timestamp = Timestamp}, + State) -> + handle_stats(connection_stats, Stats, Timestamp, {[], false}, + ?COARSE_CONN_STATS, ?PROCESS_STATS, State); + +handle_event(Event = #event{type = connection_closed, + props = [{pid, Pid}]}, _State) -> + delete_samples(connection_stats, Pid), + handle_deleted(connection_stats, Event); + +handle_event(#event{type = channel_created, props = Stats}, _State) -> + handle_created(channel_stats, Stats, {[], false}); + +handle_event(#event{type = channel_stats, props = Stats, timestamp = Timestamp}, + State) -> + handle_stats(channel_stats, Stats, Timestamp, + {fun rabbit_mgmt_format:format_channel_stats/1, true}, + [], ?PROCESS_STATS, State), + ChPid = id(channel_stats, Stats), + AllStats = [old_fine_stats(ChPid, Type, Stats) + || Type <- ?FINE_STATS_TYPES], + Objs = ets:lookup(old_stats_fine_index, ChPid), + ets:delete(old_stats_fine_index, ChPid), + [ets:delete(old_stats, Key) || {_, Key} <- Objs], + %% This ceil must correspond to the ceil in handle_event + %% queue_deleted + handle_fine_stats_list(ChPid, ceil(Timestamp, State), State, AllStats); + +handle_event(Event = #event{type = channel_closed, + props = [{pid, Pid}]}, + _State) -> + delete_consumers(Pid, consumers_by_channel, consumers_by_queue), + delete_samples(channel_queue_stats, {Pid, '_'}), + delete_samples(channel_exchange_stats, {Pid, '_'}), + delete_samples(channel_stats, Pid), + handle_deleted(channel_stats, Event), + Objs = ets:lookup(old_stats_fine_index, Pid), + ets:delete(old_stats_fine_index, Pid), + [ets:delete(old_stats, Key) || {_, Key} <- Objs]; + +handle_event(#event{type = consumer_created, props = Props}, _State) -> + Fmt = {fun rabbit_mgmt_format:format_arguments/1, true}, + handle_consumer(fun(Table, Id, P0) -> + P = rabbit_mgmt_format:format(P0, Fmt), + ets:insert(Table, {Id, P}) + end, + Props); + +handle_event(#event{type = consumer_deleted, props = Props}, _State) -> + handle_consumer(fun(Table, Id, _P) -> ets:delete(Table, Id) end, + Props); + +%% TODO: we don't clear up after dead nodes here - this is a very tiny +%% leak every time a node is permanently removed from the cluster. Do +%% we care? +handle_event(#event{type = node_stats, props = Stats0, timestamp = Timestamp}, + State) -> + Stats = proplists:delete(persister_stats, Stats0) ++ + pget(persister_stats, Stats0), + handle_stats(node_stats, Stats, Timestamp, {[], false}, ?COARSE_NODE_STATS, State); + +handle_event(#event{type = node_node_stats, props = Stats, + timestamp = Timestamp}, State) -> + handle_stats(node_node_stats, Stats, Timestamp, {[], false}, ?COARSE_NODE_NODE_STATS, + State); + +handle_event(Event = #event{type = node_node_deleted, + props = [{route, Route}]}, _State) -> + delete_samples(node_node_stats, Route), + handle_deleted(node_node_stats, Event); + +handle_event(_Event, _State) -> + ok. + +%%---------------------------------------------------------------------------- +%% Internal functions +%%---------------------------------------------------------------------------- +handle_stats(TName, Stats, Timestamp, Funs, RatesKeys, State) -> + handle_stats(TName, Stats, Timestamp, Funs, RatesKeys, [], State). + +handle_stats(TName, Stats, Timestamp, Funs, RatesKeys, NoAggRatesKeys, + State) -> + Id = id(TName, Stats), + IdSamples = {coarse, {TName, Id}}, + OldStats = lookup_element(old_stats, IdSamples), + append_set_of_samples( + Stats, Timestamp, OldStats, IdSamples, RatesKeys, NoAggRatesKeys, State), + StripKeys = [id_name(TName)] ++ RatesKeys ++ ?FINE_STATS_TYPES, + Stats1 = [{K, V} || {K, V} <- Stats, not lists:member(K, StripKeys), + V =/= unknown], + Stats2 = rabbit_mgmt_format:format(Stats1, Funs), + ets:insert(TName, {{Id, stats}, Stats2, Timestamp}), + ok. + +fine_stats_id(ChPid, {Q, X}) -> {ChPid, Q, X}; +fine_stats_id(ChPid, QorX) -> {ChPid, QorX}. + +ceil(TS, #state{interval = Interval}) -> + rabbit_mgmt_util:ceil(TS, Interval). + +handle_created(TName, Stats, Funs) -> + Formatted = rabbit_mgmt_format:format(Stats, Funs), + Id = id(TName, Stats), + ets:insert(TName, {{Id, create}, Formatted, pget(name, Stats)}), + case lists:member(TName, ?PROC_STATS_TABLES) of + true -> ets:insert(rabbit_mgmt_stats_tables:key_index(TName), {Id}); + false -> true + end. + +handle_deleted(TName, #event{props = Props}) -> + Id = id(TName, Props), + case lists:member(TName, ?TABLES) of + true -> ets:delete(TName, {Id, create}), + ets:delete(TName, {Id, stats}); + false -> ok + end, + ets:delete(old_stats, {coarse, {TName, Id}}), + case lists:member(TName, ?PROC_STATS_TABLES) of + true -> ets:delete(rabbit_mgmt_stats_tables:key_index(TName), Id); + false -> true + end. + +handle_consumer(Fun, Props) -> + P = rabbit_mgmt_format:format(Props, {[], false}), + CTag = pget(consumer_tag, P), + Q = pget(queue, P), + Ch = pget(channel, P), + Fun(consumers_by_queue, {Q, Ch, CTag}, P), + Fun(consumers_by_channel, {Ch, Q, CTag}, P). + +%% The consumer_deleted event is emitted by queues themselves - +%% therefore in the event that a queue dies suddenly we may not get +%% it. The best way to handle this is to make sure we also clean up +%% consumers when we hear about any queue going down. +delete_consumers(PrimId, PrimTableName, SecTableName) -> + SecIdCTags = ets:match(PrimTableName, {{PrimId, '$1', '$2'}, '_'}), + ets:match_delete(PrimTableName, {{PrimId, '_', '_'}, '_'}), + delete_consumers_entry(PrimId, SecTableName, SecIdCTags). + +delete_consumers_entry(PrimId, SecTableName, [[SecId, CTag] | SecIdTags]) -> + ets:delete(SecTableName, {SecId, PrimId, CTag}), + delete_consumers_entry(PrimId, SecTableName, SecIdTags); +delete_consumers_entry(_PrimId, _SecTableName, []) -> + ok. + +old_fine_stats(ChPid, Type, Props) -> + case pget(Type, Props) of + unknown -> ignore; + AllFineStats0 -> [begin + Id = fine_stats_id(ChPid, Ids), + {{fine, Id}, Stats, lookup_element(old_stats, {fine, Id})} + end || {Ids, Stats} <- AllFineStats0] + end. + +handle_fine_stats_list(ChPid, Timestamp, State, [AllStatsElem | AllStats]) -> + handle_fine_stats(ChPid, Timestamp, AllStatsElem, State), + handle_fine_stats_list(ChPid, Timestamp, State, AllStats); +handle_fine_stats_list(_ChPid, _Timestamp, _State, []) -> + ok. + +handle_fine_stats(_ChPid, _Timestamp, ignore, _State) -> + ok; +handle_fine_stats(ChPid, Timestamp, [{Id, Stats, OldStats} | AllStats], State) -> + Total = lists:sum([V || {K, V} <- Stats, lists:member(K, ?DELIVER_GET)]), + Stats1 = case Total of + 0 -> Stats; + _ -> [{deliver_get, Total}|Stats] + end, + append_all_samples(Timestamp, OldStats, Id, true, State, Stats1), + ets:insert(old_stats, {Id, Stats1}), + ets:insert(old_stats_fine_index, {ChPid, Id}), + handle_fine_stats(ChPid, Timestamp, AllStats, State); +handle_fine_stats(_ChPid, _Timestamp, [], _State) -> + ok. + +delete_samples(Type, Id0) -> + [rabbit_mgmt_stats:delete_stats(Table, Id0) + || {Table, _} <- rabbit_mgmt_stats_tables:aggr_tables(Type)]. + +append_set_of_samples(Stats, TS, OldStats, Id, Keys, NoAggKeys, State) -> + %% Refactored to avoid duplicated calls to ignore_coarse_sample, ceil and + %% ets:insert(old_stats ...) + case ignore_coarse_sample(Id, State) of + false -> + %% This ceil must correspond to the ceil in handle_event + %% queue_deleted + NewMS = ceil(TS, State), + append_samples_by_keys( + Stats, NewMS, OldStats, Id, Keys, true, State), + append_samples_by_keys( + Stats, NewMS, OldStats, Id, NoAggKeys, false, State), + ets:insert(old_stats, {Id, Stats}); + true -> + ok + end. + +append_samples_by_keys(Stats, TS, OldStats, Id, Keys, Agg, State) -> + case Keys of + all -> + append_all_samples(TS, OldStats, Id, Agg, State, Stats); + _ -> + append_some_samples(TS, OldStats, Id, Agg, State, Stats, Keys) + end. + +append_some_samples(NewMS, OldStats, Id, Agg, State, Stats, [K | Keys]) -> + V = pget(K, Stats), + case V =/= 0 orelse lists:member(K, ?ALWAYS_REPORT_STATS) of + true -> + append_sample(K, V, NewMS, OldStats, Id, Agg, State); + false -> + ok + end, + append_some_samples(NewMS, OldStats, Id, Agg, State, Stats, Keys); +append_some_samples(_NewMS, _OldStats, _Id, _Agg, _State, _Stats, []) -> + ok. + +append_all_samples(NewMS, OldStats, Id, Agg, State, [{K, 0} | Stats]) -> + case lists:member(K, ?ALWAYS_REPORT_STATS) of + true -> + append_sample(K, 0, NewMS, OldStats, Id, Agg, State); + false -> + ok + end, + append_all_samples(NewMS, OldStats, Id, Agg, State, Stats); +append_all_samples(NewMS, OldStats, Id, Agg, State, [{K, V} | Stats]) -> + append_sample(K, V, NewMS, OldStats, Id, Agg, State), + append_all_samples(NewMS, OldStats, Id, Agg, State, Stats); +append_all_samples(_NewMS, _OldStats, _Id, _Agg, _State, []) -> + ok. + +append_sample(Key, Val, NewMS, OldStats, Id, Agg, State) when is_number(Val) -> + OldVal = case pget(Key, OldStats, 0) of + N when is_number(N) -> N; + _ -> 0 + end, + record_sample(Id, {Key, Val - OldVal, NewMS, State}, Agg, State), + ok; +append_sample(_Key, _Value, _NewMS, _OldStats, _Id, _Agg, _State) -> + ok. + +ignore_coarse_sample({coarse, {queue_stats, Q}}, State) -> + not object_exists(Q, State); +ignore_coarse_sample(_, _) -> + false. + + +record_sample_list(Id, OldStats, TS, State, [Key | Keys]) -> + record_sample(Id, {Key, -pget(Key, OldStats, 0), TS, State}, true, State), + record_sample_list(Id, OldStats, TS, State, Keys); +record_sample_list(_Id, _OldStats, _TS, _State, []) -> + ok. + +%% Node stats do not have a vhost of course +record_sample({coarse, {node_stats, _Node} = Id}, Args, true, _State) -> + record_sample0(Id, Args); + +record_sample({coarse, {node_node_stats, _Names} = Id}, Args, true, _State) -> + record_sample0(Id, Args); + +record_sample({coarse, Id}, Args, false, _State) -> + record_sample0(Id, Args); + +record_sample({coarse, Id}, Args, true, _State) -> + record_sample0(Id, Args), + record_sample0({vhost_stats, vhost(Id)}, Args); + +%% Deliveries / acks (Q -> Ch) +record_sample({fine, {Ch, Q = #resource{kind = queue}}}, Args, true, State) -> + case object_exists(Q, State) of + true -> record_sample0({channel_queue_stats, {Ch, Q}}, Args), + record_sample0({queue_stats, Q}, Args); + false -> ok + end, + record_sample0({channel_stats, Ch}, Args), + record_sample0({vhost_stats, vhost(Q)}, Args); + +%% Publishes / confirms (Ch -> X) +record_sample({fine, {Ch, X = #resource{kind = exchange}}}, Args, true,State) -> + case object_exists(X, State) of + true -> record_sample0({channel_exchange_stats, {Ch, X}}, Args), + record_sampleX(publish_in, X, Args); + false -> ok + end, + record_sample0({channel_stats, Ch}, Args), + record_sample0({vhost_stats, vhost(X)}, Args); + +%% Publishes (but not confirms) (Ch -> X -> Q) +record_sample({fine, {_Ch, + Q = #resource{kind = queue}, + X = #resource{kind = exchange}}}, Args, true, State) -> + %% TODO This one logically feels like it should be here. It would + %% correspond to "publishing channel message rates to queue" - + %% which would be nice to handle - except we don't. And just + %% uncommenting this means it gets merged in with "consuming + %% channel delivery from queue" - which is not very helpful. + %% record_sample0({channel_queue_stats, {Ch, Q}}, Args), + QExists = object_exists(Q, State), + XExists = object_exists(X, State), + case QExists of + true -> record_sample0({queue_stats, Q}, Args); + false -> ok + end, + case QExists andalso XExists of + true -> record_sample0({queue_exchange_stats, {Q, X}}, Args); + false -> ok + end, + case XExists of + true -> record_sampleX(publish_out, X, Args); + false -> ok + end. + +%% We have to check the queue and exchange objects still exist since +%% their deleted event could be overtaken by a channel stats event +%% which contains fine stats referencing them. That's also why we +%% don't need to check the channels exist - their deleted event can't +%% be overtaken by their own last stats event. +%% +%% Also, sometimes the queue_deleted event is not emitted by the queue +%% (in the nodedown case) - so it can overtake the final queue_stats +%% event (which is not *guaranteed* to be lost). So we make a similar +%% check for coarse queue stats. +%% +%% We can be sure that mnesia will be up to date by the time we receive +%% the event (even though we dirty read) since the deletions are +%% synchronous and we do not emit the deleted event until after the +%% deletion has occurred. +object_exists(Name = #resource{kind = Kind}, #state{lookups = Lookups}) -> + case (pget(Kind, Lookups))(Name) of + {ok, _} -> true; + _ -> false + end. + +vhost(#resource{virtual_host = VHost}) -> + VHost; +vhost({queue_stats, #resource{virtual_host = VHost}}) -> + VHost; +vhost({TName, Pid}) -> + pget(vhost, lookup_element(TName, {Pid, create})). + +%% exchanges have two sets of "publish" stats, so rearrange things a touch +record_sampleX(RenamePublishTo, X, {publish, Diff, TS, State}) -> + record_sample0({exchange_stats, X}, {RenamePublishTo, Diff, TS, State}); +record_sampleX(_RenamePublishTo, X, {Type, Diff, TS, State}) -> + record_sample0({exchange_stats, X}, {Type, Diff, TS, State}). + +%% Ignore case where ID1 and ID2 are in a tuple, i.e. detailed stats, +%% when in basic mode +record_sample0({Type, {_ID1, _ID2}}, {_, _, _, #state{rates_mode = basic}}) + when Type =/= node_node_stats -> + ok; +record_sample0({Type, Id0}, {Key0, Diff, TS, #state{}}) -> + {Key, Pos} = stat_type(Key0), + Id = {Id0, TS}, + rabbit_mgmt_stats:record(Id, Pos, Diff, Key, + rabbit_mgmt_stats_tables:aggr_table(Type, Key)). + +%%------------------------------------------------------------------------------ +%% @hidden +%% @doc Returns the type of the stat and the position in the tuple +%% +%% Uses the record definitions for simplicity, keeping track of the positions in +%% the tuple. +%% @end +%%------------------------------------------------------------------------------ +stat_type(deliver) -> + {deliver_get, #deliver_get.deliver}; +stat_type(deliver_no_ack) -> + {deliver_get, #deliver_get.deliver_no_ack}; +stat_type(get) -> + {deliver_get, #deliver_get.get}; +stat_type(get_no_ack) -> + {deliver_get, #deliver_get.get_no_ack}; +stat_type(publish) -> + {fine_stats, #fine_stats.publish}; +stat_type(publish_in) -> + {fine_stats, #fine_stats.publish_in}; +stat_type(publish_out) -> + {fine_stats, #fine_stats.publish_out}; +stat_type(ack) -> + {fine_stats, #fine_stats.ack}; +stat_type(deliver_get) -> + {fine_stats, #fine_stats.deliver_get}; +stat_type(confirm) -> + {fine_stats, #fine_stats.confirm}; +stat_type(return_unroutable) -> + {fine_stats, #fine_stats.return_unroutable}; +stat_type(redeliver) -> + {fine_stats, #fine_stats.redeliver}; +stat_type(disk_reads) -> + {queue_msg_rates, #queue_msg_rates.disk_reads}; +stat_type(disk_writes) -> + {queue_msg_rates, #queue_msg_rates.disk_writes}; +stat_type(messages) -> + {queue_msg_counts, #queue_msg_counts.messages}; +stat_type(messages_ready) -> + {queue_msg_counts, #queue_msg_counts.messages_ready}; +stat_type(messages_unacknowledged) -> + {queue_msg_counts, #queue_msg_counts.messages_unacknowledged}; +stat_type(mem_used) -> + {coarse_node_stats, #coarse_node_stats.mem_used}; +stat_type(fd_used) -> + {coarse_node_stats, #coarse_node_stats.fd_used}; +stat_type(sockets_used) -> + {coarse_node_stats, #coarse_node_stats.sockets_used}; +stat_type(proc_used) -> + {coarse_node_stats, #coarse_node_stats.proc_used}; +stat_type(disk_free) -> + {coarse_node_stats, #coarse_node_stats.disk_free}; +stat_type(io_read_count) -> + {coarse_node_stats, #coarse_node_stats.io_read_count}; +stat_type(io_read_bytes) -> + {coarse_node_stats, #coarse_node_stats.io_read_bytes}; +stat_type(io_read_time) -> + {coarse_node_stats, #coarse_node_stats.io_read_time}; +stat_type(io_write_count) -> + {coarse_node_stats, #coarse_node_stats.io_write_count}; +stat_type(io_write_bytes) -> + {coarse_node_stats, #coarse_node_stats.io_write_bytes}; +stat_type(io_write_time) -> + {coarse_node_stats, #coarse_node_stats.io_write_time}; +stat_type(io_sync_count) -> + {coarse_node_stats, #coarse_node_stats.io_sync_count}; +stat_type(io_sync_time) -> + {coarse_node_stats, #coarse_node_stats.io_sync_time}; +stat_type(io_seek_count) -> + {coarse_node_stats, #coarse_node_stats.io_seek_count}; +stat_type(io_seek_time) -> + {coarse_node_stats, #coarse_node_stats.io_seek_time}; +stat_type(io_reopen_count) -> + {coarse_node_stats, #coarse_node_stats.io_reopen_count}; +stat_type(mnesia_ram_tx_count) -> + {coarse_node_stats, #coarse_node_stats.mnesia_ram_tx_count}; +stat_type(mnesia_disk_tx_count) -> + {coarse_node_stats, #coarse_node_stats.mnesia_disk_tx_count}; +stat_type(msg_store_read_count) -> + {coarse_node_stats, #coarse_node_stats.msg_store_read_count}; +stat_type(msg_store_write_count) -> + {coarse_node_stats, #coarse_node_stats.msg_store_write_count}; +stat_type(queue_index_journal_write_count) -> + {coarse_node_stats, #coarse_node_stats.queue_index_journal_write_count}; +stat_type(queue_index_write_count) -> + {coarse_node_stats, #coarse_node_stats.queue_index_write_count}; +stat_type(queue_index_read_count) -> + {coarse_node_stats, #coarse_node_stats.queue_index_read_count}; +stat_type(gc_num) -> + {coarse_node_stats, #coarse_node_stats.gc_num}; +stat_type(gc_bytes_reclaimed) -> + {coarse_node_stats, #coarse_node_stats.gc_bytes_reclaimed}; +stat_type(context_switches) -> + {coarse_node_stats, #coarse_node_stats.context_switches}; +stat_type(send_bytes) -> + {coarse_node_node_stats, #coarse_node_node_stats.send_bytes}; +stat_type(recv_bytes) -> + {coarse_node_node_stats, #coarse_node_node_stats.recv_bytes}; +stat_type(recv_oct) -> + {coarse_conn_stats, #coarse_conn_stats.recv_oct}; +stat_type(send_oct) -> + {coarse_conn_stats, #coarse_conn_stats.send_oct}; +stat_type(reductions) -> + {process_stats, #process_stats.reductions}; +stat_type(io_file_handle_open_attempt_count) -> + {coarse_node_stats, #coarse_node_stats.io_file_handle_open_attempt_count}; +stat_type(io_file_handle_open_attempt_time) -> + {coarse_node_stats, #coarse_node_stats.io_file_handle_open_attempt_time}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_extension.erl b/deps/rabbitmq_management/src/rabbit_mgmt_extension.erl similarity index 63% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_extension.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_extension.erl index 6d12cde..b558c40 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_extension.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_extension.erl @@ -16,10 +16,17 @@ -module(rabbit_mgmt_extension). -%% Return a Cowboy dispatcher table to integrate --callback dispatcher() -> [{string(), atom(), [atom()]}]. +-export([behaviour_info/1]). -%% Return a proplist of information for the web UI to integrate -%% this extension. Currently the proplist should have one key, -%% 'javascript', the name of a javascript file to load and run. --callback web_ui() -> proplists:proplist(). +behaviour_info(callbacks) -> + [ + %% Return a webmachine dispatcher table to integrate + {dispatcher, 0}, + + %% Return a proplist of information for the web UI to integrate + %% this extension. Currently the proplist should have one key, + %% 'javascript', the name of a javascript file to load and run. + {web_ui, 0} + ]; +behaviour_info(_Other) -> + undefined. diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_format.erl b/deps/rabbitmq_management/src/rabbit_mgmt_format.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_format.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_format.erl index 33a06a9..6323738 100644 --- a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_format.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_format.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_format). @@ -21,22 +21,19 @@ -export([protocol/1, resource/1, queue/1, queue_state/1]). -export([exchange/1, user/1, internal_user/1, binding/1, url/2]). -export([pack_binding_props/2, tokenise/1]). --export([to_amqp_table/1, listener/1, web_context/1, properties/1, basic_properties/1]). +-export([to_amqp_table/1, listener/1, properties/1, basic_properties/1]). -export([record/2, to_basic_properties/1]). -export([addr/1, port/1]). --export([format_nulls/1, escape_html_tags/1]). +-export([format_nulls/1]). -export([print/2, print/1]). -export([format_queue_stats/1, format_channel_stats/1, - format_consumer_arguments/1, format_arguments/1, format_connection_created/1, format_accept_content/1, format_args/1]). -export([strip_queue_pids/1]). --export([clean_consumer_details/1, clean_channel_details/1]). - --import(rabbit_misc, [pget/2, pget/3, pset/3]). +-import(rabbit_misc, [pget/2, pset/3]). -include_lib("rabbit_common/include/rabbit.hrl"). -include_lib("rabbit_common/include/rabbit_framing.hrl"). @@ -69,10 +66,6 @@ format_queue_stats({idle_since, Value}) -> [{idle_since, now_to_str(Value)}]; format_queue_stats({state, Value}) -> queue_state(Value); -format_queue_stats({disk_reads, _}) -> - []; -format_queue_stats({disk_writes, _}) -> - []; format_queue_stats(Stat) -> [Stat]. @@ -87,7 +80,7 @@ format_arguments(Stat) -> Stat. format_args({arguments, Value}) -> - {arguments, args(Value)}; + {arguments, rabbit_mgmt_util:args(Value)}; format_args(Stat) -> Stat. @@ -128,11 +121,11 @@ format_basic_properties(Stat) -> Stat. format_accept_content({durable, Value}) -> - {durable, parse_bool(Value)}; + {durable, rabbit_mgmt_util:parse_bool(Value)}; format_accept_content({auto_delete, Value}) -> - {auto_delete, parse_bool(Value)}; + {auto_delete, rabbit_mgmt_util:parse_bool(Value)}; format_accept_content({internal, Value}) -> - {internal, parse_bool(Value)}; + {internal, rabbit_mgmt_util:parse_bool(Value)}; format_accept_content(Stat) -> Stat. @@ -176,7 +169,7 @@ amqp_value(_Type, V) -> V. utf8_safe(V) -> try - _ = xmerl_ucs:from_utf8(V), + xmerl_ucs:from_utf8(V), V catch exit:{ucs, _} -> Enc = split_lines(base64:encode(V)), @@ -249,71 +242,18 @@ tags(Tags) -> list_to_binary(string:join([atom_to_list(T) || T <- Tags], ",")). listener(#listener{node = Node, protocol = Protocol, - ip_address = IPAddress, port = Port, opts=Opts}) -> + ip_address = IPAddress, port = Port}) -> [{node, Node}, {protocol, Protocol}, {ip_address, ip(IPAddress)}, - {port, Port}, - {socket_opts, format_socket_opts(Opts)}]. - -web_context(Props0) -> - SslOpts = pget(ssl_opts, Props0, []), - Props = proplists:delete(ssl_opts, Props0), - [{ssl_opts, format_socket_opts(SslOpts)} | Props]. - -format_socket_opts(Opts) -> - format_socket_opts(Opts, []). - -format_socket_opts([], Acc) -> - lists:reverse(Acc); -%% for HTTP API listeners this will be included into -%% socket_opts -format_socket_opts([{ssl_opts, Value} | Tail], Acc) -> - format_socket_opts(Tail, [{ssl_opts, format_socket_opts(Value)} | Acc]); -%% exclude options that have values that are nested -%% data structures or may include functions. They are fairly -%% obscure and not worth reporting via HTTP API. -format_socket_opts([{verify_fun, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([{crl_cache, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([{partial_chain, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([{user_lookup_fun, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([{sni_fun, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([{reuse_session, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -%% we do not want to report configured cipher suites, even -%% though formatting them is straightforward -format_socket_opts([{ciphers, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -%% single atom options, e.g. `binary` -format_socket_opts([Head | Tail], Acc) when is_atom(Head) -> - format_socket_opts(Tail, [{Head, true} | Acc]); -%% verify_fun value is a tuple that includes a function -format_socket_opts([_Head = {verify_fun, _Value} | Tail], Acc) -> - format_socket_opts(Tail, Acc); -format_socket_opts([Head = {Name, Value} | Tail], Acc) when is_list(Value) -> - case io_lib:printable_unicode_list(Value) of - true -> format_socket_opts(Tail, [{Name, unicode:characters_to_binary(Value)} | Acc]); - false -> format_socket_opts(Tail, [Head | Acc]) - end; -format_socket_opts([{Name, Value} | Tail], Acc) when is_tuple(Value) -> - format_socket_opts(Tail, [{Name, tuple_to_list(Value)} | Acc]); -%% exclude functions from JSON encoding -format_socket_opts([_Head = {_Name, Value} | Tail], Acc) when is_function(Value) -> - format_socket_opts(Tail, Acc); -format_socket_opts([Head | Tail], Acc) -> - format_socket_opts(Tail, [Head | Acc]). + {port, Port}]. pack_binding_props(<<"">>, []) -> <<"~">>; pack_binding_props(Key, []) -> list_to_binary(quote_binding(Key)); pack_binding_props(Key, Args) -> - ArgsEnc = args_hash(Args), + ArgsEnc = rabbit_mgmt_wm_binding:args_hash(Args), list_to_binary(quote_binding(Key) ++ "~" ++ quote_binding(ArgsEnc)). quote_binding(Name) -> @@ -417,7 +357,7 @@ to_basic_properties({struct, P}) -> to_basic_properties(P); to_basic_properties(Props) -> - E = fun err/2, + E = fun (A, B) -> throw({error, {A, B}}) end, Fmt = fun (headers, H) -> to_amqp_table(H); (delivery_mode, V) when is_integer(V) -> V; (delivery_mode, _V) -> E(not_int,delivery_mode); @@ -438,10 +378,6 @@ to_basic_properties(Props) -> record_info(fields, 'P_basic')), Res. --spec err(term(), term()) -> no_return(). -err(A, B) -> - throw({error, {A, B}}). - a2b(A) -> list_to_binary(atom_to_list(A)). @@ -480,8 +416,6 @@ strip_pids([{owner_pid, _} | T], Acc) -> strip_pids(T, Acc); strip_pids([{channel, _} | T], Acc) -> strip_pids(T, Acc); -strip_pids([{channel_pid, _} | T], Acc) -> - strip_pids(T, Acc); strip_pids([{exclusive_consumer_pid, _} | T], Acc) -> strip_pids(T, Acc); strip_pids([{slave_pids, ''} | T], Acc) -> @@ -492,10 +426,6 @@ strip_pids([{synchronised_slave_pids, ''} | T], Acc) -> strip_pids(T, Acc); strip_pids([{synchronised_slave_pids, Pids} | T], Acc) -> strip_pids(T, [{synchronised_slave_nodes, [node(Pid) || Pid <- Pids]} | Acc]); -strip_pids([{K, [P|_] = Nested} | T], Acc) when is_tuple(P) -> % recurse - strip_pids(T, [{K, strip_pids(Nested)} | Acc]); -strip_pids([{K, [L|_] = Nested} | T], Acc) when is_list(L) -> % recurse - strip_pids(T, [{K, strip_pids(Nested)} | Acc]); strip_pids([Any | T], Acc) -> strip_pids(T, [Any | Acc]); strip_pids([], Acc) -> @@ -521,67 +451,3 @@ format_null_item([{_K, _V} | _T] = L) -> format_nulls(L); format_null_item(Value) -> Value. - - --spec escape_html_tags(string()) -> binary(). - -escape_html_tags(S) -> - escape_html_tags(rabbit_data_coercion:to_list(S), []). - - --spec escape_html_tags(string(), string()) -> binary(). - -escape_html_tags([], Acc) -> - rabbit_data_coercion:to_binary(lists:reverse(Acc)); -escape_html_tags("<" ++ Rest, Acc) -> - escape_html_tags(Rest, lists:reverse("<", Acc)); -escape_html_tags(">" ++ Rest, Acc) -> - escape_html_tags(Rest, lists:reverse(">", Acc)); -escape_html_tags("&" ++ Rest, Acc) -> - escape_html_tags(Rest, lists:reverse("&", Acc)); -escape_html_tags([C | Rest], Acc) -> - escape_html_tags(Rest, [C | Acc]). - - --spec clean_consumer_details(proplists:proplist()) -> proplists:proplist(). -clean_consumer_details(Obj) -> - case pget(consumer_details, Obj) of - undefined -> Obj; - Cds -> - Cons = [format_consumer_arguments(clean_channel_details(Con)) || Con <- Cds], - pset(consumer_details, Cons, Obj) - end. - --spec clean_channel_details(proplists:proplist()) -> proplists:proplist(). -clean_channel_details(Obj) -> - Obj0 = lists:keydelete(channel_pid, 1, Obj), - case pget(channel_details, Obj0) of - undefined -> Obj0; - Chd -> - pset(channel_details, - lists:keydelete(pid, 1, Chd), - Obj0) - end. - --spec format_consumer_arguments(proplists:proplist()) -> proplists:proplist(). -format_consumer_arguments(Obj) -> - case pget(arguments, Obj) of - undefined -> Obj; - [] -> pset(arguments, {struct, []}, Obj); - Args -> pset(arguments, amqp_table(Args), Obj) - end. - -%% Converts a proplist into an AMQP 0-9-1 table. -%% For JSON serialisation formatting see amqp_table/1. -args({struct, L}) -> args(L); -args(L) -> to_amqp_table(L). - -parse_bool(<<"true">>) -> true; -parse_bool(<<"false">>) -> false; -parse_bool(true) -> true; -parse_bool(false) -> false; -parse_bool(undefined) -> undefined; -parse_bool(V) -> throw({error, {not_boolean, V}}). - -args_hash(Args) -> - list_to_binary(rabbit_misc:base64url(erlang:md5(term_to_binary(Args)))). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl b/deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl index ccc050c..d52e8ac 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_load_definitions.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_load_definitions). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_queue_stats_collector.erl b/deps/rabbitmq_management/src/rabbit_mgmt_queue_stats_collector.erl new file mode 100644 index 0000000..1d4602e --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_queue_stats_collector.erl @@ -0,0 +1,120 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_queue_stats_collector). + +-include("rabbit_mgmt.hrl"). +-include("rabbit_mgmt_metrics.hrl"). +-include("rabbit_mgmt_event_collector.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +-behaviour(gen_server2). + +-export([start_link/0]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3, handle_pre_hibernate/1]). + +-export([prioritise_cast/3]). + +-import(rabbit_misc, [pget/3]). +-import(rabbit_mgmt_db, [pget/2, id_name/1, id/2, lookup_element/2]). + +prioritise_cast({event, #event{type = queue_stats}}, Len, + #state{max_backlog = MaxBacklog} = _State) + when Len > MaxBacklog -> + drop; +prioritise_cast(_Msg, _Len, _State) -> + 0. + +%% See the comment on rabbit_mgmt_db for the explanation of +%% events and stats. + +%% Although this gen_server could process all types of events through the +%% handle_cast, rabbit_mgmt_db_handler (in the management agent) forwards +%% only the non-prioritiy events channel_stats +%%---------------------------------------------------------------------------- +%% API +%%---------------------------------------------------------------------------- + +start_link() -> + case gen_server2:start_link({global, ?MODULE}, ?MODULE, [], []) of + {ok, Pid} -> register(?MODULE, Pid), %% [1] + {ok, Pid}; + Else -> Else + end. +%% [1] For debugging it's helpful to locally register the name too +%% since that shows up in places global names don't. + +%%---------------------------------------------------------------------------- +%% Internal, gen_server2 callbacks +%%---------------------------------------------------------------------------- + +init([]) -> + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + {ok, RatesMode} = application:get_env(rabbitmq_management, rates_mode), + {ok, MaxBacklog} = application:get_env(rabbitmq_management, + stats_event_max_backlog), + process_flag(priority, high), + rabbit_log:info("Statistics queue stats collector started.~n"), + {ok, reset_lookups( + #state{interval = Interval, + rates_mode = RatesMode, + max_backlog = MaxBacklog}), hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. + +%% Used in rabbit_mgmt_test_db where we need guarantees events have +%% been handled before querying +handle_call({event, Event = #event{reference = none}}, _From, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + reply(ok, State); + +handle_call(_Request, _From, State) -> + reply(not_understood, State). + +%% Only handle events that are real. +handle_cast({event, Event = #event{reference = none}}, State) -> + rabbit_mgmt_event_collector_utils:handle_event(Event, State), + noreply(State); + +handle_cast(_Request, State) -> + noreply(State). + +handle_info(_Info, State) -> + noreply(State). + +terminate(_Arg, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +reply(Reply, NewState) -> {reply, Reply, NewState, hibernate}. +noreply(NewState) -> {noreply, NewState, hibernate}. + +reset_lookups(State) -> + State#state{lookups = [{exchange, fun rabbit_exchange:lookup/1}, + {queue, fun rabbit_amqqueue:lookup/1}]}. + +handle_pre_hibernate(State) -> + %% rabbit_event can end up holding on to some memory after a busy + %% workout, but it's not a gen_server so we can't make it + %% hibernate. The best we can do is forcibly GC it here (if + %% rabbit_mgmt_db is hibernating the odds are rabbit_event is + %% quiescing in some way too). + rpc:multicall( + rabbit_mnesia:cluster_nodes(running), rabbit_mgmt_db_handler, gc, []), + {hibernate, State}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl b/deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl index 071bf7f..40008f0 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_reset_handler.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% When management extensions are enabled and/or disabled at runtime, the @@ -51,9 +51,7 @@ handle_event(#event{type = plugins_changed, props = Details}, State) -> Enabled = pget(enabled, Details), Disabled = pget(disabled, Details), case extensions_changed(Enabled ++ Disabled) of - true -> - _ = rabbit_mgmt_app:reset_dispatcher(Disabled), - ok; + true -> rabbit_mgmt_app:reset_dispatcher(Disabled); false -> ok end, {ok, State}; diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_stats.erl b/deps/rabbitmq_management/src/rabbit_mgmt_stats.erl new file mode 100644 index 0000000..af8f310 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_stats.erl @@ -0,0 +1,978 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2010-2012 GoPivotal, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_stats). + +-include("rabbit_mgmt.hrl"). +-include("rabbit_mgmt_metrics.hrl"). + +-export([blank/1, is_blank/3, record/5, format/5, sum/1, gc/3, + free/1, delete_stats/2, get_keys/2]). + +-import(rabbit_misc, [pget/2]). + +-define(ALWAYS_REPORT, [queue_msg_counts, coarse_node_stats]). +-define(MICRO_TO_MILLI, 1000). + +%% Data is stored in ETS tables: +%% * one set of ETS tables per event (queue_stats, queue_exchange_stats...) +%% * each set contains one table per group of events (queue_msg_rates, +%% deliver_get, fine_stats...) such as aggr_queue_stats_deliver_get +%% (see ?AGGR_TABLES in rabbit_mgmt_metrics.hrl) +%% * data is then stored as a tuple (not a record) to take advantage of the +%% atomic call ets:update_counter/3. The equivalent records are noted in +%% rabbit_mgmt_metrics.hrl to get the position and as reference for developers +%% * Records are of the shape: +%% {{Id, base}, Field1, Field2, ....} +%% {{Id, total}, Field1, Field2, ....} +%% {{Id, Timestamp}, Field1, Field2, ....} +%% where Id can be a simple key or a tuple {Id0, Id1} +%% +%% This module is not generic any longer, any new event or field needs to be +%% manually added, but it increases the performance and allows concurrent +%% GC, event collection and querying +%% + +%%---------------------------------------------------------------------------- +%% External functions +%%---------------------------------------------------------------------------- + +blank(Name) -> + ets:new(rabbit_mgmt_stats_tables:index(Name), + [bag, public, named_table]), + ets:new(rabbit_mgmt_stats_tables:key_index(Name), + [ordered_set, public, named_table]), + ets:new(Name, [set, public, named_table]). + +is_blank({Table, _, _}, Id, Record) -> + is_blank(Table, Id, Record); +is_blank(Table, Id, Record) -> + case ets:lookup(Table, {Id, total}) of + [] -> + true; + [Total] -> + case lists:member(Record, ?ALWAYS_REPORT) of + true -> false; + false -> is_blank(Total) + end + end. + +%%---------------------------------------------------------------------------- +free({Table, IndexTable, KeyIndexTable}) -> + ets:delete(Table), + ets:delete(IndexTable), + ets:delete(KeyIndexTable). + +delete_stats(Table, {'_', _} = Id) -> + delete_complex_stats(Table, Id); +delete_stats(Table, {_, '_'} = Id) -> + delete_complex_stats(Table, Id); +delete_stats(Table, Id) -> + Keys = full_indexes(Table, Id), + ets:delete(rabbit_mgmt_stats_tables:index(Table), Id), + ets:delete(rabbit_mgmt_stats_tables:key_index(Table), Id), + [ets:delete(Table, Key) || Key <- Keys]. + +delete_complex_stats(Table, Id) -> + Ids = ets:select(rabbit_mgmt_stats_tables:key_index(Table), + match_spec_key_index(Id)), + delete_complex_stats_loop(Table, Ids). + +delete_complex_stats_loop(_Table, []) -> + ok; +delete_complex_stats_loop(Table, [{Id} | Ids]) -> + delete_stats(Table, Id), + delete_complex_stats_loop(Table, Ids). + +%%---------------------------------------------------------------------------- +get_keys(Table, Id0) -> + ets:select(rabbit_mgmt_stats_tables:key_index(Table), match_spec_keys(Id0)). + +%%---------------------------------------------------------------------------- +%% Event-time +%%---------------------------------------------------------------------------- + +record({Id, _TS} = Key, Pos, Diff, Record, Table) -> + ets_update(Table, Key, Record, Pos, Diff), + ets_update(Table, {Id, total}, Record, Pos, Diff). + +%%---------------------------------------------------------------------------- +%% Query-time +%%---------------------------------------------------------------------------- + +format(no_range, Table, Id, Interval, Type) -> + Now = time_compat:os_system_time(milli_seconds), + Counts = get_value(Table, Id, total, Type), + RangePoint = ((Now div Interval) * Interval) - Interval, + {Record, Factor} = format_rate_with( + Table, Id, RangePoint, Interval, Interval, Type), + format_rate(Type, Record, Counts, Factor); + +format(Range, Table, Id, Interval, Type) -> + Base = get_value(Table, Id, base, Type), + RangePoint = Range#range.last - Interval, + {Samples, Counts} = extract_samples(Range, Base, Table, Id, Type), + {Record, Factor} = format_rate_with( + Table, Id, RangePoint, Range#range.incr, Interval, Type), + format_rate(Type, Record, Counts, Samples, Factor). + +sum([]) -> blank(); + +sum([{T1, Id} | StatsN]) -> + {Table, IndexTable, KeyIndexTable} = T = blank(), + AllIds = full_indexes(T1, Id), + lists:foreach(fun(Index) -> + case ets:lookup(T1, Index) of + [V] -> + {_, TS} = element(1, V), + ets:insert(Table, setelement(1, V, {all, TS})), + insert_index(IndexTable, KeyIndexTable, {all, TS}); + [] -> %% base + ok + end + end, AllIds), + sum(StatsN, T). + +sum(StatsN, T) -> + lists:foreach( + fun ({T1, Id}) -> + AllIds = full_indexes(T1, Id), + lists:foreach(fun(Index) -> + case ets:lookup(T1, Index) of + [V] -> + {_, TS} = element(1, V), + ets_update(T, {all, TS}, V); + [] -> %% base + ok + end + end, AllIds) + end, StatsN), + T. + +gc(Cutoff, Table, Id) -> + gc(Cutoff, lists:reverse(indexes(Table, Id)), Table, undefined). + +%%---------------------------------------------------------------------------- +%% Internal functions +%%---------------------------------------------------------------------------- +format_rate_with({Table, IndexTable, _KeyIndexTable}, Id, RangePoint, Incr, + Interval, Type) -> + format_rate_with(Table, IndexTable, Id, RangePoint, Incr, Interval, Type); +format_rate_with(Table, Id, RangePoint, Incr, Interval, Type) -> + format_rate_with(Table, rabbit_mgmt_stats_tables:index(Table), Id, + RangePoint, Incr, Interval, Type). + +format_rate_with(Table, IndexTable, Id, RangePoint, Incr, Interval, Type) -> + case second_largest(Table, IndexTable, Id) of + [S] -> + {_, TS} = element(1, S), + case TS - RangePoint of %% [0] + D when D =< Incr andalso D >= 0 -> {S, Interval}; + _ -> {S, 0.0} + end; + _ -> + {empty(Id, Type), 0.0} + end. + +%% [0] Only display the rate if it's live - i.e. ((the end of the +%% range) - interval) corresponds to the second to last data point we +%% have. If the end of the range is earlier we have gone silent, if +%% it's later we have been asked for a range back in time (in which +%% case showing the correct instantaneous rate would be quite a faff, +%% and probably unwanted). Why the second to last? Because data is +%% still arriving for the last... +second_largest(Table, IndexTable, Id) -> + case ets:lookup(IndexTable, Id) of + [_, _ | _] = List -> + ets:lookup(Table, sl(List, {none, 0}, {none, 0})); + _ -> + unknown + end. + +sl([{_, TS} = H | T], {_, T1} = L1, _L2) when TS > T1 -> + sl(T, H, L1); +sl([{_, TS} = H | T], L1, {_, T2}) when TS > T2 -> + sl(T, L1, H); +sl([_ | T], L1, L2) -> + sl(T, L1, L2); +sl([], _L1, L2) -> + L2. + +%% What we want to do here is: given the #range{}, provide a set of +%% samples such that we definitely provide a set of samples which +%% covers the exact range requested, despite the fact that we might +%% not have it. We need to spin up over the entire range of the +%% samples we *do* have since they are diff-based (and we convert to +%% absolute values here). +extract_samples(Range, Base, Table, Id, Type) -> + %% In order to calculate the average operation time for some of the node + %% metrics, it needs to carry around the last raw sample taken (before + %% calculations). This is the first element of the 'Samples' tuple. + %% It is initialised to the base, which is updated with the latest value until + %% it finds the first valid sample. Thus, generating an instant rate for it. + %% Afterwards, it will store the last raw sample. + extract_samples0(Range, Base, indexes(Table, Id), Table, Type, + {Base, empty_list(Type)}). + +extract_samples0(Range = #range{first = Next}, Base, [], Table, Type, Samples) -> + %% [3] Empty or finished table + extract_samples1(Range, Base, empty({unused_id, Next}, Type), [], Table, Type, + Samples); +extract_samples0(Range, Base, [Index | List], Tab, Type, Samples) -> + Table = case Tab of + {T, _, _} -> + T; + T -> + T + end, + case ets:lookup(Table, Index) of + [S] -> + extract_samples1(Range, Base, S, List, Table, Type, Samples); + [] -> + extract_samples0(Range, Base, List, Table, Type, Samples) + end. + +extract_samples1(Range = #range{first = Next, last = Last, incr = Incr}, + Base, S, List, Table, Type, {LastRawSample, Samples}) -> + {_, TS} = element(1, S), + if + %% We've gone over the range. Terminate. + Next > Last -> + %% Drop the raw sample + {Samples, Base}; + %% We've hit bang on a sample. Record it and move to the next. + Next =:= TS -> + %% The new base is the last sample used to generate instant rates + %% in the node stats + NewBase = add_record(Base, S), + extract_samples0(Range#range{first = Next + Incr}, NewBase, List, + Table, Type, {NewBase, append(NewBase, Samples, Next, + LastRawSample)}); + %% We haven't yet hit the beginning of our range. + Next > TS -> + NewBase = add_record(Base, S), + %% Roll the latest value until we find the first sample + RawSample = case element(2, Samples) of + [] -> NewBase; + _ -> LastRawSample + end, + extract_samples0(Range, NewBase, List, Table, Type, + {RawSample, Samples}); + %% We have a valid sample, but we haven't used it up + %% yet. Append it and loop around. + Next < TS -> + %% Pass the last raw sample to calculate instant node stats + extract_samples1(Range#range{first = Next + Incr}, Base, S, + List, Table, Type, + {Base, append(Base, Samples, Next, LastRawSample)}) + end. + +append({_Key, V1}, {samples, V1s}, TiS, _LastRawSample) -> + {samples, append_sample(V1, TiS, V1s)}; +append({_Key, V1, V2}, {samples, V1s, V2s}, TiS, _LastRawSample) -> + {samples, append_sample(V1, TiS, V1s), append_sample(V2, TiS, V2s)}; +append({_Key, V1, V2, V3}, {samples, V1s, V2s, V3s}, TiS, _LastRawSample) -> + {samples, append_sample(V1, TiS, V1s), append_sample(V2, TiS, V2s), + append_sample(V3, TiS, V3s)}; +append({_Key, V1, V2, V3, V4}, {samples, V1s, V2s, V3s, V4s}, TiS, _LastRawSample) -> + {samples, append_sample(V1, TiS, V1s), append_sample(V2, TiS, V2s), + append_sample(V3, TiS, V3s), append_sample(V4, TiS, V4s)}; +append({_Key, V1, V2, V3, V4, V5, V6, V7, V8}, + {samples, V1s, V2s, V3s, V4s, V5s, V6s, V7s, V8s}, TiS, _LastRawSample) -> + {samples, append_sample(V1, TiS, V1s), append_sample(V2, TiS, V2s), + append_sample(V3, TiS, V3s), append_sample(V4, TiS, V4s), + append_sample(V5, TiS, V5s), append_sample(V6, TiS, V6s), + append_sample(V7, TiS, V7s), append_sample(V8, TiS, V8s)}; +append({_Key, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, V15, + V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28}, + {samples, V1s, V2s, V3s, V4s, V5s, V6s, V7s, V8s, V9s, V10s, V11s, V12s, + V13s, V14s, V15s, V16s, V17s, V18s, V19s, V20s, V21s, V22s, V23s, V24s, + V25s, V26s, V27s, V28s}, + TiS, + {_, _V1r, _V2r, _V3r, _V4r, _V5r, V6r, _V7r, V8r, V9r, _V10r, V11r, + V12r, V13r, V14r, V15r, _V16r, _V17r, _V18r, _V19r, _V20r, _V21r, + _V22r, _V23r, _V24r, _V25r, _V26r, V27r, V28r}) -> + %% This clause covers the coarse node stats, which must calculate the average + %% operation times for read, write, sync and seek. These differ from any other + %% statistic and must be caculated using the total time and counter of operations. + %% By calculating the new sample against the last sampled point, we provide + %% instant averages that truly reflect the behaviour of the system + %% during that space of time. + {samples, append_sample(V1, TiS, V1s), append_sample(V2, TiS, V2s), + append_sample(V3, TiS, V3s), append_sample(V4, TiS, V4s), + append_sample(V5, TiS, V5s), append_sample(V6, TiS, V6s), + append_sample(V7, TiS, V7s), + append_sample(avg_time(V8, V6, V8r, V6r), TiS, V8s), + append_sample(V9, TiS, V9s), append_sample(V10, TiS, V10s), + append_sample(avg_time(V11, V9, V11r, V9r), TiS, V11s), + append_sample(V12, TiS, V12s), + append_sample(avg_time(V13, V12, V13r, V12r), TiS, V13s), + append_sample(V14, TiS, V14s), + append_sample(avg_time(V15, V14, V15r, V14r), TiS, V15s), + append_sample(V16, TiS, V16s), + append_sample(V17, TiS, V17s), append_sample(V18, TiS, V18s), + append_sample(V19, TiS, V19s), append_sample(V20, TiS, V20s), + append_sample(V21, TiS, V21s), append_sample(V22, TiS, V22s), + append_sample(V23, TiS, V23s), append_sample(V24, TiS, V24s), + append_sample(V25, TiS, V25s), append_sample(V26, TiS, V26s), + append_sample(V27, TiS, V27s), + append_sample(avg_time(V28, V27, V28r, V27r), TiS, V28s)}. + +append_sample(S, TS, List) -> + [[{sample, S}, {timestamp, TS}] | List]. + +blank() -> + Table = ets:new(rabbit_mgmt_stats, [ordered_set, public]), + Index = ets:new(rabbit_mgmt_stats, [bag, public]), + KeyIndex = ets:new(rabbit_mgmt_stats, [ordered_set, public]), + {Table, Index, KeyIndex}. + +%%---------------------------------------------------------------------------- +%% Event-GCing +%%---------------------------------------------------------------------------- +%% Go through the list, amalgamating all too-old samples with the next +%% newest keepable one [0] (we move samples forward in time since the +%% semantics of a sample is "we had this many x by this time"). If the +%% sample is too old, but would not be too old if moved to a rounder +%% timestamp which does not exist then invent one and move it there +%% [1]. But if it's just outright too old, move it to the base [2]. +gc(_Cutoff, [], _Table, _Keep) -> + ok; +gc(Cutoff, [Index | T], Table, Keep) -> + case ets:lookup(Table, Index) of + [S] -> + {Id, TS} = Key = element(1, S), + Keep1 = case keep(Cutoff, TS) of + keep -> + TS; + drop -> %% [2] + ets_update(Table, {Id, base}, S), + ets_delete_value(Table, Key), + Keep; + {move, D} when Keep =:= undefined -> %% [1] + ets_update(Table, {Id, TS + D}, S), + ets_delete_value(Table, Key), + TS + D; + {move, _} -> %% [0] + ets_update(Table, {Id, Keep}, S), + ets_delete_value(Table, Key), + Keep + end, + gc(Cutoff, T, Table, Keep1); + _ -> + gc(Cutoff, T, Table, Keep) + end. + +keep({Policy, Now}, TS) -> + lists:foldl(fun ({AgeSec, DivisorSec}, Action) -> + prefer_action( + Action, + case (Now - TS) =< (AgeSec * 1000) of + true -> DivisorMillis = DivisorSec * 1000, + case TS rem DivisorMillis of + 0 -> keep; + Rem -> {move, DivisorMillis - Rem} + end; + false -> drop + end) + end, drop, Policy). + +prefer_action(keep, _) -> keep; +prefer_action(_, keep) -> keep; +prefer_action({move, A}, {move, B}) -> {move, lists:min([A, B])}; +prefer_action({move, A}, drop) -> {move, A}; +prefer_action(drop, {move, A}) -> {move, A}; +prefer_action(drop, drop) -> drop. + +%%---------------------------------------------------------------------------- +%% ETS update +%%---------------------------------------------------------------------------- +ets_update(Table, K, R, P, V) -> + try + ets:update_counter(Table, K, {P, V}) + catch + _:_ -> + ets:insert(Table, new_record(K, R, P, V)), + insert_index(Table, K) + end. + +insert_index(Table, Key) -> + insert_index(rabbit_mgmt_stats_tables:index(Table), + rabbit_mgmt_stats_tables:key_index(Table), + Key). + +insert_index(_, _, {_, V}) when is_atom(V) -> + ok; +insert_index(Index, KeyIndex, {Id, _TS} = Key) -> + ets:insert(Index, Key), + ets:insert(KeyIndex, {Id}). + +ets_update({Table, IndexTable, KeyIndexTable}, Key, Record) -> + try + ets:update_counter(Table, Key, record_to_list(Record)) + catch + _:_ -> + ets:insert(Table, setelement(1, Record, Key)), + insert_index(IndexTable, KeyIndexTable, Key) + end; +ets_update(Table, Key, Record) -> + try + ets:update_counter(Table, Key, record_to_list(Record)) + catch + _:_ -> + ets:insert(Table, setelement(1, Record, Key)), + insert_index(Table, Key) + end. + +new_record(K, deliver_get, P, V) -> + setelement(P, {K, 0, 0, 0, 0}, V); +new_record(K, fine_stats, P, V) -> + setelement(P, {K, 0, 0, 0, 0, 0, 0, 0, 0}, V); +new_record(K, queue_msg_rates, P, V) -> + setelement(P, {K, 0, 0}, V); +new_record(K, queue_msg_counts, P, V) -> + setelement(P, {K, 0, 0, 0}, V); +new_record(K, coarse_node_stats, P, V) -> + setelement(P, {K, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0}, V); +new_record(K, coarse_node_node_stats, P, V) -> + setelement(P, {K, 0, 0}, V); +new_record(K, coarse_conn_stats, P, V) -> + setelement(P, {K, 0, 0}, V); +new_record(K, process_stats, P, V) -> + setelement(P, {K, 0}, V). + +%% Returns a list of {Position, Increment} to update the current record +record_to_list({_Key, V1}) -> + [{2, V1}]; +record_to_list({_Key, V1, V2}) -> + [{2, V1}, {3, V2}]; +record_to_list({_Key, V1, V2, V3}) -> + [{2, V1}, {3, V2}, {4, V3}]; +record_to_list({_Key, V1, V2, V3, V4}) -> + [{2, V1}, {3, V2}, {4, V3}, {5, V4}]; +record_to_list({_Key, V1, V2, V3, V4, V5, V6, V7, V8}) -> + [{2, V1}, {3, V2}, {4, V3}, {5, V4}, {6, V5}, {7, V6}, {8, V7}, {9, V8}]; +record_to_list({_Key, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, + V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, + V26, V27, V28}) -> + [{2, V1}, {3, V2}, {4, V3}, {5, V4}, {6, V5}, {7, V6}, {8, V7}, {9, V8}, + {10, V9}, {11, V10}, {12, V11}, {13, V12}, {14, V13}, {15, V14}, + {16, V15}, {17, V16}, {18, V17}, {19, V18}, {20, V19}, {21, V20}, + {22, V21}, {23, V22}, {24, V23}, {25, V24}, {26, V25}, {27, V26}, + {28, V27}, {29, V28}]. + +%%---------------------------------------------------------------------------- + +get_value({Table, _, _}, Id, Tag, Type) -> + get_value(Table, Id, Tag, Type); +get_value(Table, Id, Tag, Type) -> + Key = {Id, Tag}, + case ets:lookup(Table, Key) of + [] -> empty(Key, Type); + [Elem] -> Elem + end. + +ets_delete_value(Table, Key) -> + ets:delete_object(rabbit_mgmt_stats_tables:index(Table), Key), + ets:delete(Table, Key). + +indexes({_, Index, _}, Id) -> + lists:sort(ets:lookup(Index, Id)); +indexes(Table, Id) -> + lists:sort(ets:lookup(rabbit_mgmt_stats_tables:index(Table), Id)). + +full_indexes(Table, Id) -> + full_indexes(Table, rabbit_mgmt_stats_tables:index(Table), Id). + +full_indexes(_Table, Index, Id) -> + Indexes = ets:lookup(Index, Id), + [{Id, base}, {Id, total} | Indexes]. + +%%---------------------------------------------------------------------------- +%% Match specs to select or delete from the ETS tables +%%---------------------------------------------------------------------------- +match_spec_key_index(Id) -> + MatchHead = {partial_match(Id)}, + Id0 = to_simple_match_spec(Id), + [{MatchHead, [{'==', Id0, '$1'}],['$_']}]. + +partial_match({_Id0, '_'}) -> + {'$1', '_'}; +partial_match({'_', _Id1}) -> + {'_', '$1'}. + +to_simple_match_spec({Id0, '_'}) when is_tuple(Id0) -> + {Id0}; +to_simple_match_spec({'_', Id1}) when is_tuple(Id1) -> + {Id1}; +to_simple_match_spec({Id0, '_'}) -> + Id0; +to_simple_match_spec({'_', Id1}) -> + Id1; +to_simple_match_spec(Id) when is_tuple(Id) -> + {Id}; +to_simple_match_spec(Id) -> + Id. + +to_match_condition({'_', Id1}) when is_tuple(Id1) -> + {'==', {Id1}, '$2'}; +to_match_condition({'_', Id1}) -> + {'==', Id1, '$2'}; +to_match_condition({Id0, '_'}) when is_tuple(Id0) -> + {'==', {Id0}, '$1'}; +to_match_condition({Id0, '_'}) -> + {'==', Id0, '$1'}. + +match_spec_keys(Id) -> + MatchCondition = to_match_condition(Id), + MatchHead = {{'$1', '$2'}}, + [{MatchHead, [MatchCondition], [{{'$1', '$2'}}]}]. + +%%---------------------------------------------------------------------------- +%% Format output +%%---------------------------------------------------------------------------- +format_rate(deliver_get, {_, D, DN, G, GN}, {_, TD, TDN, TG, TGN}, Factor) -> + [ + {deliver, TD}, {deliver_details, [{rate, apply_factor(D, Factor)}]}, + {deliver_no_ack, TDN}, + {deliver_no_ack_details, [{rate, apply_factor(DN, Factor)}]}, + {get, TG}, {get_details, [{rate, apply_factor(G, Factor)}]}, + {get_no_ack, TGN}, + {get_no_ack_details, [{rate, apply_factor(GN, Factor)}]} + ]; +format_rate(fine_stats, {_, P, PI, PO, A, D, C, RU, R}, + {_, TP, TPI, TPO, TA, TD, TC, TRU, TR}, Factor) -> + [ + {publish, TP}, {publish_details, [{rate, apply_factor(P, Factor)}]}, + {publish_in, TPI}, + {publish_in_details, [{rate, apply_factor(PI, Factor)}]}, + {publish_out, TPO}, + {publish_out_details, [{rate, apply_factor(PO, Factor)}]}, + {ack, TA}, {ack_details, [{rate, apply_factor(A, Factor)}]}, + {deliver_get, TD}, {deliver_get_details, [{rate, apply_factor(D, Factor)}]}, + {confirm, TC}, {confirm_details, [{rate, apply_factor(C, Factor)}]}, + {return_unroutable, TRU}, + {return_unroutable_details, [{rate, apply_factor(RU, Factor)}]}, + {redeliver, TR}, {redeliver_details, [{rate, apply_factor(R, Factor)}]} + ]; +format_rate(queue_msg_rates, {_, R, W}, {_, TR, TW}, Factor) -> + [ + {disk_reads, TR}, {disk_reads_details, [{rate, apply_factor(R, Factor)}]}, + {disk_writes, TW}, {disk_writes_details, [{rate, apply_factor(W, Factor)}]} + ]; +format_rate(queue_msg_counts, {_, M, MR, MU}, {_, TM, TMR, TMU}, Factor) -> + [ + {messages, TM}, + {messages_details, [{rate, apply_factor(M, Factor)}]}, + {messages_ready, TMR}, + {messages_ready_details, [{rate, apply_factor(MR, Factor)}]}, + {messages_unacknowledged, TMU}, + {messages_unacknowledged_details, [{rate, apply_factor(MU, Factor)}]} + ]; +format_rate(coarse_node_stats, + {_, M, F, S, P, D, IR, IB, IA, IWC, IWB, IWAT, IS, ISAT, ISC, + ISEAT, IRC, MRTC, MDTC, MSRC, MSWC, QIJWC, QIWC, QIRC, GC, GCW, CS, + IO, IOAT}, + {_, TM, TF, TS, TP, TD, TIR, TIB, TIA, TIWC, TIWB, TIWAT, TIS, + TISAT, TISC, TISEAT, TIRC, TMRTC, TMDTC, TMSRC, TMSWC, TQIJWC, + TQIWC, TQIRC, TGC, TGCW, TCS, TIO, TIOAT}, Factor) -> + %% Calculates average times for read/write/sync/seek from the + %% accumulated time and count + %% io__avg_time is the average operation time for the life of the node + %% io__avg_time_details/rate is the average operation time during the + %% last time unit calculated (thus similar to an instant rate) + [ + {mem_used, TM}, + {mem_used_details, [{rate, apply_factor(M, Factor)}]}, + {fd_used, TF}, + {fd_used_details, [{rate, apply_factor(F, Factor)}]}, + {sockets_used, TS}, + {sockets_used_details, [{rate, apply_factor(S, Factor)}]}, + {proc_used, TP}, + {proc_used_details, [{rate, apply_factor(P, Factor)}]}, + {disk_free, TD}, + {disk_free_details, [{rate, apply_factor(D, Factor)}]}, + {io_read_count, TIR}, + {io_read_count_details, [{rate, apply_factor(IR, Factor)}]}, + {io_read_bytes, TIB}, + {io_read_bytes_details, [{rate, apply_factor(IB, Factor)}]}, + {io_read_avg_time, avg_time(TIA, TIR)}, + {io_read_avg_time_details, [{rate, avg_time(IA, IR)}]}, + {io_write_count, TIWC}, + {io_write_count_details, [{rate, apply_factor(IWC, Factor)}]}, + {io_write_bytes, TIWB}, + {io_write_bytes_details, [{rate, apply_factor(IWB, Factor)}]}, + {io_write_avg_time, avg_time(TIWAT, TIWC)}, + {io_write_avg_time_details, [{rate, avg_time(IWAT, IWC)}]}, + {io_sync_count, TIS}, + {io_sync_count_details, [{rate, apply_factor(IS, Factor)}]}, + {io_sync_avg_time, avg_time(TISAT, TIS)}, + {io_sync_avg_time_details, [{rate, avg_time(ISAT, IS)}]}, + {io_seek_count, TISC}, + {io_seek_count_details, [{rate, apply_factor(ISC, Factor)}]}, + {io_seek_avg_time, avg_time(TISEAT, TISC)}, + {io_seek_avg_time_details, [{rate, avg_time(ISEAT, ISC)}]}, + {io_reopen_count, TIRC}, + {io_reopen_count_details, [{rate, apply_factor(IRC, Factor)}]}, + {mnesia_ram_tx_count, TMRTC}, + {mnesia_ram_tx_count_details, [{rate, apply_factor(MRTC, Factor)}]}, + {mnesia_disk_tx_count, TMDTC}, + {mnesia_disk_tx_count_details, [{rate, apply_factor(MDTC, Factor)}]}, + {msg_store_read_count, TMSRC}, + {msg_store_read_count_details, [{rate, apply_factor(MSRC, Factor)}]}, + {msg_store_write_count, TMSWC}, + {msg_store_write_count_details, [{rate, apply_factor(MSWC, Factor)}]}, + {queue_index_journal_write_count, TQIJWC}, + {queue_index_journal_write_count_details, [{rate, apply_factor(QIJWC, Factor)}]}, + {queue_index_write_count, TQIWC}, + {queue_index_write_count_details, [{rate, apply_factor(QIWC, Factor)}]}, + {queue_index_read_count, TQIRC}, + {queue_index_read_count_details, [{rate, apply_factor(QIRC, Factor)}]}, + {gc_num, TGC}, + {gc_num_details, [{rate, apply_factor(GC, Factor)}]}, + {gc_bytes_reclaimed, TGCW}, + {gc_bytes_reclaimed_details, [{rate, apply_factor(GCW, Factor)}]}, + {context_switches, TCS}, + {context_switches_details, [{rate, apply_factor(CS, Factor)}]}, + {io_file_handle_open_attempt_count, TIO}, + {io_file_handle_open_attempt_count_details, [{rate, apply_factor(IO, Factor)}]}, + {io_file_handle_open_attempt_avg_time, avg_time(TIOAT, TIO)}, + {io_file_handle_open_attempt_avg_time_details, [{rate, avg_time(IOAT, IO)}]} + ]; +format_rate(coarse_node_node_stats, {_, S, R}, {_, TS, TR}, Factor) -> + [ + {send_bytes, TS}, + {send_bytes_details, [{rate, apply_factor(S, Factor)}]}, + {send_bytes, TR}, + {send_bytes_details, [{rate, apply_factor(R, Factor)}]} + ]; +format_rate(coarse_conn_stats, {_, R, S}, {_, TR, TS}, Factor) -> + [ + {send_oct, TS}, + {send_oct_details, [{rate, apply_factor(S, Factor)}]}, + {recv_oct, TR}, + {recv_oct_details, [{rate, apply_factor(R, Factor)}]} + ]; +format_rate(process_stats, {_, R}, {_, TR}, Factor) -> + [ + {reductions, TR}, + {reductions_details, [{rate, apply_factor(R, Factor)}]} + ]. + +format_rate(deliver_get, {_, D, DN, G, GN}, {_, TD, TDN, TG, TGN}, + {_, SD, SDN, SG, SGN}, Factor) -> + Length = length(SD), + [ + {deliver, TD}, {deliver_details, [{rate, apply_factor(D, Factor)}, + {samples, SD}] ++ average(SD, Length)}, + {deliver_no_ack, TDN}, + {deliver_no_ack_details, [{rate, apply_factor(DN, Factor)}, + {samples, SDN}] ++ average(SDN, Length)}, + {get, TG}, {get_details, [{rate, apply_factor(G, Factor)}, + {samples, SG}] ++ average(SG, Length)}, + {get_no_ack, TGN}, + {get_no_ack_details, [{rate, apply_factor(GN, Factor)}, + {samples, SGN}] ++ average(SGN, Length)} + ]; +format_rate(fine_stats, {_, P, PI, PO, A, D, C, RU, R}, + {_, TP, TPI, TPO, TA, TD, TC, TRU, TR}, + {_, SP, SPI, SPO, SA, SD, SC, SRU, SR}, Factor) -> + Length = length(SP), + [ + {publish, TP}, + {publish_details, [{rate, apply_factor(P, Factor)}, + {samples, SP}] ++ average(SP, Length)}, + {publish_in, TPI}, + {publish_in_details, [{rate, apply_factor(PI, Factor)}, + {samples, SPI}] ++ average(SPI, Length)}, + {publish_out, TPO}, + {publish_out_details, [{rate, apply_factor(PO, Factor)}, + {samples, SPO}] ++ average(SPO, Length)}, + {ack, TA}, {ack_details, [{rate, apply_factor(A, Factor)}, + {samples, SA}] ++ average(SA, Length)}, + {deliver_get, TD}, + {deliver_get_details, [{rate, apply_factor(D, Factor)}, + {samples, SD}] ++ average(SD, Length)}, + {confirm, TC}, + {confirm_details, [{rate, apply_factor(C, Factor)}, + {samples, SC}] ++ average(SC, Length)}, + {return_unroutable, TRU}, + {return_unroutable_details, [{rate, apply_factor(RU, Factor)}, + {samples, SRU}] ++ average(SRU, Length)}, + {redeliver, TR}, + {redeliver_details, [{rate, apply_factor(R, Factor)}, + {samples, SR}] ++ average(SR, Length)} + ]; +format_rate(queue_msg_rates, {_, R, W}, {_, TR, TW}, {_, SR, SW}, Factor) -> + Length = length(SR), + [ + {disk_reads, TR}, + {disk_reads_details, [{rate, apply_factor(R, Factor)}, + {samples, SR}] ++ average(SR, Length)}, + {disk_writes, TW}, + {disk_writes_details, [{rate, apply_factor(W, Factor)}, + {samples, SW}] ++ average(SW, Length)} + ]; +format_rate(queue_msg_counts, {_, M, MR, MU}, {_, TM, TMR, TMU}, + {_, SM, SMR, SMU}, Factor) -> + Length = length(SM), + [ + {messages, TM}, + {messages_details, [{rate, apply_factor(M, Factor)}, + {samples, SM}] ++ average(SM, Length)}, + {messages_ready, TMR}, + {messages_ready_details, [{rate, apply_factor(MR, Factor)}, + {samples, SMR}] ++ average(SMR, Length)}, + {messages_unacknowledged, TMU}, + {messages_unacknowledged_details, [{rate, apply_factor(MU, Factor)}, + {samples, SMU}] ++ average(SMU, Length)} + ]; +format_rate(coarse_node_stats, + {_, M, F, S, P, D, IR, IB, IA, IWC, IWB, IWAT, IS, ISAT, ISC, + ISEAT, IRC, MRTC, MDTC, MSRC, MSWC, QIJWC, QIWC, QIRC, GC, GCW, CS, + IO, IOAT}, + {_, TM, TF, TS, TP, TD, TIR, TIB, TIA, TIWC, TIWB, TIWAT, TIS, + TISAT, TISC, TISEAT, TIRC, TMRTC, TMDTC, TMSRC, TMSWC, TQIJWC, + TQIWC, TQIRC, TGC, TGCW, TCS, TIO, TIOAT}, + {_, SM, SF, SS, SP, SD, SIR, SIB, SIA, SIWC, SIWB, SIWAT, SIS, + SISAT, SISC, SISEAT, SIRC, SMRTC, SMDTC, SMSRC, SMSWC, SQIJWC, + SQIWC, SQIRC, SGC, SGCW, SCS, SIO, SIOAT}, Factor) -> + %% Calculates average times for read/write/sync/seek from the + %% accumulated time and count. + %% io__avg_time is the average operation time for the life of the node. + %% io__avg_time_details/rate is the average operation time during the + %% last time unit calculated (thus similar to an instant rate). + %% io__avg_time_details/samples contain the average operation time + %% during each time unit requested. + %% io__avg_time_details/avg_rate is meaningless here, but we keep it + %% to maintain an uniform API with all the other metrics. + %% io__avg_time_details/avg is the average of the samples taken over + %% the requested period of time. + Length = length(SM), + [ + {mem_used, TM}, + {mem_used_details, [{rate, apply_factor(M, Factor)}, + {samples, SM}] ++ average(SM, Length)}, + {fd_used, TF}, + {fd_used_details, [{rate, apply_factor(F, Factor)}, + {samples, SF}] ++ average(SF, Length)}, + {sockets_used, TS}, + {sockets_used_details, [{rate, apply_factor(S, Factor)}, + {samples, SS}] ++ average(SS, Length)}, + {proc_used, TP}, + {proc_used_details, [{rate, apply_factor(P, Factor)}, + {samples, SP}] ++ average(SP, Length)}, + {disk_free, TD}, + {disk_free_details, [{rate, apply_factor(D, Factor)}, + {samples, SD}] ++ average(SD, Length)}, + {io_read_count, TIR}, + {io_read_count_details, [{rate, apply_factor(IR, Factor)}, + {samples, SIR}] ++ average(SIR, Length)}, + {io_read_bytes, TIB}, + {io_read_bytes_details, [{rate, apply_factor(IB, Factor)}, + {samples, SIB}] ++ average(SIB, Length)}, + {io_read_avg_time, avg_time(TIA, TIR)}, + {io_read_avg_time_details, [{rate, avg_time(IA, IR)}, + {samples, SIA}] ++ average(SIA, Length)}, + {io_write_count, TIWC}, + {io_write_count_details, [{rate, apply_factor(IWC, Factor)}, + {samples, SIWC}] ++ average(SIWC, Length)}, + {io_write_bytes, TIWB}, + {io_write_bytes_details, [{rate, apply_factor(IWB, Factor)}, + {samples, SIWB}] ++ average(SIWB, Length)}, + {io_write_avg_time, avg_time(TIWAT, TIWC)}, + {io_write_avg_time_details, [{rate, avg_time(IWAT, TIWC)}, + {samples, SIWAT}] ++ average(SIWAT, Length)}, + {io_sync_count, TIS}, + {io_sync_count_details, [{rate, apply_factor(IS, Factor)}, + {samples, SIS}] ++ average(SIS, Length)}, + {io_sync_avg_time, avg_time(TISAT, TIS)}, + {io_sync_avg_time_details, [{rate, avg_time(ISAT, IS)}, + {samples, SISAT}] ++ average(SISAT, Length)}, + {io_seek_count, TISC}, + {io_seek_count_details, [{rate, apply_factor(ISC, Factor)}, + {samples, SISC}] ++ average(SISC, Length)}, + {io_seek_avg_time, avg_time(TISEAT, TISC)}, + {io_seek_avg_time_details, [{rate, avg_time(ISEAT, ISC)}, + {samples, SISEAT}] ++ average(SISEAT, Length)}, + {io_reopen_count, TIRC}, + {io_reopen_count_details, [{rate, apply_factor(IRC, Factor)}, + {samples, SIRC}] ++ average(SIRC, Length)}, + {mnesia_ram_tx_count, TMRTC}, + {mnesia_ram_tx_count_details, [{rate, apply_factor(MRTC, Factor)}, + {samples, SMRTC}] ++ average(SMRTC, Length)}, + {mnesia_disk_tx_count, TMDTC}, + {mnesia_disk_tx_count_details, [{rate, apply_factor(MDTC, Factor)}, + {samples, SMDTC}] ++ average(SMDTC, Length)}, + {msg_store_read_count, TMSRC}, + {msg_store_read_count_details, [{rate, apply_factor(MSRC, Factor)}, + {samples, SMSRC}] ++ average(SMSRC, Length)}, + {msg_store_write_count, TMSWC}, + {msg_store_write_count_details, [{rate, apply_factor(MSWC, Factor)}, + {samples, SMSWC}] ++ average(SMSWC, Length)}, + {queue_index_journal_write_count, TQIJWC}, + {queue_index_journal_write_count_details, + [{rate, apply_factor(QIJWC, Factor)}, + {samples, SQIJWC}] ++ average(SQIJWC, Length)}, + {queue_index_write_count, TQIWC}, + {queue_index_write_count_details, [{rate, apply_factor(QIWC, Factor)}, + {samples, SQIWC}] ++ average(SQIWC, Length)}, + {queue_index_read_count, TQIRC}, + {queue_index_read_count_details, [{rate, apply_factor(QIRC, Factor)}, + {samples, SQIRC}] ++ average(SQIRC, Length)}, + {gc_num, TGC}, + {gc_num_details, [{rate, apply_factor(GC, Factor)}, + {samples, SGC}] ++ average(SGC, Length)}, + {gc_bytes_reclaimed, TGCW}, + {gc_bytes_reclaimed_details, [{rate, apply_factor(GCW, Factor)}, + {samples, SGCW}] ++ average(SGCW, Length)}, + {context_switches, TCS}, + {context_switches_details, [{rate, apply_factor(CS, Factor)}, + {samples, SCS}] ++ average(SCS, Length)}, + {io_file_handle_open_attempt_count, TIO}, + {io_file_handle_open_attempt_count_details, + [{rate, apply_factor(IO, Factor)}, + {samples, SIO}] ++ average(SIO, Length)}, + {io_file_handle_open_attempt_avg_time, avg_time(TIOAT, TIO)}, + {io_file_handle_open_attempt_avg_time_details, + [{rate, avg_time(IOAT, IO)}, + {samples, SIOAT}] ++ average(SIOAT, Length)} + ]; +format_rate(coarse_node_node_stats, {_, S, R}, {_, TS, TR}, {_, SS, SR}, + Factor) -> + Length = length(SS), + [ + {send_bytes, TS}, + {send_bytes_details, [{rate, apply_factor(S, Factor)}, + {samples, SS}] ++ average(SS, Length)}, + {send_bytes, TR}, + {send_bytes_details, [{rate, apply_factor(R, Factor)}, + {samples, SR}] ++ average(SR, Length)} + ]; +format_rate(coarse_conn_stats, {_, R, S}, {_, TR, TS}, {_, SR, SS}, + Factor) -> + Length = length(SS), + [ + {send_oct, TS}, + {send_oct_details, [{rate, apply_factor(S, Factor)}, + {samples, SS}] ++ average(SS, Length)}, + {recv_oct, TR}, + {recv_oct_details, [{rate, apply_factor(R, Factor)}, + {samples, SR}] ++ average(SR, Length)} + ]; +format_rate(process_stats, {_, R}, {_, TR}, {_, SR}, Factor) -> + Length = length(SR), + [ + {reductions, TR}, + {reductions_details, [{rate, apply_factor(R, Factor)}, + {samples, SR}] ++ average(SR, Length)} + ]. + +apply_factor(_, 0.0) -> + 0.0; +apply_factor(S, Factor) -> + S * 1000 / Factor. + +average(_Samples, Length) when Length =< 1 -> + []; +average(Samples, Length) -> + [{sample, S2}, {timestamp, T2}] = hd(Samples), + [{sample, S1}, {timestamp, T1}] = lists:last(Samples), + Total = lists:sum([pget(sample, I) || I <- Samples]), + [{avg_rate, (S2 - S1) * 1000 / (T2 - T1)}, + {avg, Total / Length}]. +%%---------------------------------------------------------------------------- + +add_record({Base, V1}, {_, V11}) -> + {Base, V1 + V11}; +add_record({Base, V1, V2}, {_, V11, V21}) -> + {Base, V1 + V11, V2 + V21}; +add_record({Base, V1, V2, V3}, {_, V1a, V2a, V3a}) -> + {Base, V1 + V1a, V2 + V2a, V3 + V3a}; +add_record({Base, V1, V2, V3, V4}, {_, V1a, V2a, V3a, V4a}) -> + {Base, V1 + V1a, V2 + V2a, V3 + V3a, V4 + V4a}; +add_record({Base, V1, V2, V3, V4, V5, V6, V7, V8}, + {_, V1a, V2a, V3a, V4a, V5a, V6a, V7a, V8a}) -> + {Base, V1 + V1a, V2 + V2a, V3 + V3a, V4 + V4a, V5 + V5a, V6 + V6a, V7 + V7a, + V8 + V8a}; +add_record({Base, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11, V12, V13, V14, + V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, V26, V27, V28}, + {_, V1a, V2a, V3a, V4a, V5a, V6a, V7a, V8a, V9a, V10a, V11a, V12a, + V13a, V14a, V15a, V16a, V17a, V18a, V19a, V20a, V21a, V22a, V23a, + V24a, V25a, V26a, V27a, V28a}) -> + {Base, V1 + V1a, V2 + V2a, V3 + V3a, V4 + V4a, V5 + V5a, V6 + V6a, V7 + V7a, + V8 + V8a, V9 + V9a, V10 + V10a, V11 + V11a, V12 + V12a, V13 + V13a, + V14 + V14a, V15 + V15a, V16 + V16a, V17 + V17a, V18 + V18a, V19 + V19a, + V20 + V20a, V21 + V21a, V22 + V22a, V23 + V23a, V24 + V24a, V25 + V25a, + V26 + V26a, V27 + V27a, V28 + V28a}. + +empty(Key, process_stats) -> + {Key, 0}; +empty(Key, Type) when Type == queue_msg_rates; + Type == coarse_node_node_stats; + Type == coarse_conn_stats -> + {Key, 0, 0}; +empty(Key, queue_msg_counts) -> + {Key, 0, 0, 0}; +empty(Key, deliver_get) -> + {Key, 0, 0, 0, 0}; +empty(Key, fine_stats) -> + {Key, 0, 0, 0, 0, 0, 0, 0, 0}; +empty(Key, coarse_node_stats) -> + {Key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}. + +empty_list(process_stats) -> + {samples, []}; +empty_list(Type) when Type == queue_msg_rates; + Type == coarse_node_node_stats; + Type == coarse_conn_stats -> + {samples, [], []}; +empty_list(queue_msg_counts) -> + {samples, [], [], []}; +empty_list(deliver_get) -> + {samples, [], [], [], []}; +empty_list(fine_stats) -> + {samples, [], [], [], [], [], [], [], []}; +empty_list(coarse_node_stats) -> + {samples, [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], + [], [], [], [], [], [], [], [], [], [], [], []}. + + +is_blank({_Key, 0}) -> + true; +is_blank({_Key, 0, 0}) -> + true; +is_blank({_Key, 0, 0, 0}) -> + true; +is_blank({_Key, 0, 0, 0, 0}) -> + true; +is_blank({_Key, 0, 0, 0, 0, 0, 0, 0, 0}) -> + true; +is_blank({_Key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}) -> + true; +is_blank(_) -> + false. + +avg_time(_Total, 0) -> + 0.0; +avg_time(Total, Count) -> + (Total / Count) / ?MICRO_TO_MILLI. + +avg_time(Total, Count, BaseTotal, BaseCount) -> + avg_time(Total - BaseTotal, Count - BaseCount). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_stats_gc.erl b/deps/rabbitmq_management/src/rabbit_mgmt_stats_gc.erl new file mode 100644 index 0000000..44b5277 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_stats_gc.erl @@ -0,0 +1,219 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_stats_gc). + +-include_lib("rabbit_common/include/rabbit.hrl"). +-include("rabbit_mgmt_metrics.hrl"). + +-behaviour(gen_server2). + +-export([start_link/1]). + +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, + code_change/3, handle_pre_hibernate/1]). + +-export([name/1]). + +-import(rabbit_misc, [pget/3]). +-import(rabbit_mgmt_db, [pget/2, id_name/1, id/2, lookup_element/2]). + +-record(state, { + interval, + gc_timer, + gc_table, + gc_index, + gc_next_key + }). + +-define(GC_INTERVAL, 5000). +-define(GC_MIN_ROWS, 50). +-define(GC_MIN_RATIO, 0.001). + +-define(DROP_LENGTH, 1000). + +-define(PROCESS_ALIVENESS_TIMEOUT, 15000). + +%%---------------------------------------------------------------------------- +%% API +%%---------------------------------------------------------------------------- + +start_link(Table) -> + case gen_server2:start_link({global, name(Table)}, ?MODULE, [Table], []) of + {ok, Pid} -> register(name(Table), Pid), %% [1] + {ok, Pid}; + Else -> Else + end. +%% [1] For debugging it's helpful to locally register the name too +%% since that shows up in places global names don't. + +%%---------------------------------------------------------------------------- +%% Internal, gen_server2 callbacks +%%---------------------------------------------------------------------------- + +init([Table]) -> + {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), + rabbit_log:info("Statistics garbage collector started for table ~p with interval ~p.~n", [Table, Interval]), + {ok, set_gc_timer(#state{interval = Interval, + gc_table = Table, + gc_index = rabbit_mgmt_stats_tables:key_index(Table)}), + hibernate, + {backoff, ?HIBERNATE_AFTER_MIN, ?HIBERNATE_AFTER_MIN, ?DESIRED_HIBERNATE}}. + +handle_call(_Request, _From, State) -> + reply(not_understood, State). + +handle_cast(_Request, State) -> + noreply(State). + +handle_info(gc, State) -> + noreply(set_gc_timer(gc_batch(State))); + +handle_info(_Info, State) -> + noreply(State). + +terminate(_Arg, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +reply(Reply, NewState) -> {reply, Reply, NewState, hibernate}. +noreply(NewState) -> {noreply, NewState, hibernate}. + +set_gc_timer(State) -> + TRef = erlang:send_after(?GC_INTERVAL, self(), gc), + State#state{gc_timer = TRef}. + +handle_pre_hibernate(State) -> + {hibernate, State}. + +%%---------------------------------------------------------------------------- +%% Internal, utilities +%%---------------------------------------------------------------------------- + +floor(TS, #state{interval = Interval}) -> + rabbit_mgmt_util:floor(TS, Interval). + +%%---------------------------------------------------------------------------- +%% Internal, event-GCing +%%---------------------------------------------------------------------------- + +gc_batch(#state{gc_index = Index} = State) -> + {ok, Policies} = application:get_env( + rabbitmq_management, sample_retention_policies), + {ok, ProcGCTimeout} = application:get_env( + rabbitmq_management, process_stats_gc_timeout), + Config = [{policies, Policies}, {process_stats_gc_timeout, ProcGCTimeout}], + Total = ets:info(Index, size), + Rows = erlang:max(erlang:min(Total, ?GC_MIN_ROWS), round(?GC_MIN_RATIO * Total)), + gc_batch(Rows, Config, State). + +gc_batch(0, _Config, State) -> + State; +gc_batch(Rows, Config, State = #state{gc_next_key = Cont, + gc_table = Table, + gc_index = Index}) -> + Select = case Cont of + undefined -> + ets:first(Index); + _ -> + ets:next(Index, Cont) + end, + NewCont = case Select of + '$end_of_table' -> + undefined; + Key -> + Now = floor( + time_compat:os_system_time(milli_seconds), + State), + gc(Key, Table, Config, Now), + Key + end, + gc_batch(Rows - 1, Config, State#state{gc_next_key = NewCont}). + +gc(Key, Table, Config, Now) -> + case lists:member(Table, ?PROC_STATS_TABLES) of + true -> gc_proc(Key, Table, Config, Now); + false -> gc_aggr(Key, Table, Config, Now) + end. + +gc_proc(Key, Table, Config, Now) when Table == connection_stats; + Table == channel_stats -> + Timeout = pget(process_stats_gc_timeout, Config), + case ets:lookup(Table, {Key, stats}) of + %% Key is already cleared. Skipping + [] -> ok; + [{{Key, stats}, _Stats, TS}] -> maybe_gc_process(Key, Table, + TS, Now, Timeout) + end. + +gc_aggr(Key, Table, Config, Now) -> + Policies = pget(policies, Config), + Policy = pget(retention_policy(Table), Policies), + rabbit_mgmt_stats:gc({Policy, Now}, Table, Key). + +maybe_gc_process(Pid, Table, LastStatsTS, Now, Timeout) -> + case Now - LastStatsTS < Timeout of + true -> ok; + false -> + case process_status(Pid) of + %% Process doesn't exist on remote node + undefined -> rabbit_event:notify(deleted_event(Table), + [{pid, Pid}]); + %% Remote node is unreachable or process is alive + _ -> ok + end + end. + +process_status(Pid) when node(Pid) =:= node() -> + process_info(Pid, status); +process_status(Pid) -> + rpc:block_call(node(Pid), erlang, process_info, [Pid, status], + ?PROCESS_ALIVENESS_TIMEOUT). + +deleted_event(channel_stats) -> channel_closed; +deleted_event(connection_stats) -> connection_closed. + +retention_policy(aggr_node_stats_coarse_node_stats) -> global; +retention_policy(aggr_node_node_stats_coarse_node_node_stats) -> global; +retention_policy(aggr_vhost_stats_deliver_get) -> global; +retention_policy(aggr_vhost_stats_fine_stats) -> global; +retention_policy(aggr_vhost_stats_queue_msg_rates) -> global; +retention_policy(aggr_vhost_stats_msg_rates_details) -> global; +retention_policy(aggr_vhost_stats_queue_msg_counts) -> global; +retention_policy(aggr_vhost_stats_coarse_conn_stats) -> global; +retention_policy(aggr_queue_stats_fine_stats) -> basic; +retention_policy(aggr_queue_stats_deliver_get) -> basic; +retention_policy(aggr_queue_stats_queue_msg_counts) -> basic; +retention_policy(aggr_queue_stats_queue_msg_rates) -> basic; +retention_policy(aggr_queue_stats_process_stats) -> basic; +retention_policy(aggr_exchange_stats_fine_stats) -> basic; +retention_policy(aggr_connection_stats_coarse_conn_stats) -> basic; +retention_policy(aggr_connection_stats_process_stats) -> basic; +retention_policy(aggr_channel_stats_deliver_get) -> basic; +retention_policy(aggr_channel_stats_fine_stats) -> basic; +retention_policy(aggr_channel_stats_queue_msg_counts) -> basic; +retention_policy(aggr_channel_stats_process_stats) -> basic; +retention_policy(aggr_queue_exchange_stats_fine_stats) -> detailed; +retention_policy(aggr_channel_exchange_stats_deliver_get) -> detailed; +retention_policy(aggr_channel_exchange_stats_fine_stats) -> detailed; +retention_policy(aggr_channel_queue_stats_deliver_get) -> detailed; +retention_policy(aggr_channel_queue_stats_fine_stats) -> detailed; +retention_policy(aggr_channel_queue_stats_queue_msg_counts) -> detailed. + +name(Atom) -> + list_to_atom((atom_to_list(Atom) ++ "_gc")). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_stats_tables.erl b/deps/rabbitmq_management/src/rabbit_mgmt_stats_tables.erl new file mode 100644 index 0000000..2505280 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_stats_tables.erl @@ -0,0 +1,271 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is Pivotal Software, Inc. +%% Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_stats_tables). + +-include("rabbit_mgmt_metrics.hrl"). + +-export([aggr_table/2, aggr_tables/1, type_from_table/1, + index/1, key_index/1]). + +-spec aggr_table(event_type(), type()) -> table_name(). +aggr_table(queue_stats, deliver_get) -> + aggr_queue_stats_deliver_get; +aggr_table(queue_stats, fine_stats) -> + aggr_queue_stats_fine_stats; +aggr_table(queue_stats, queue_msg_counts) -> + aggr_queue_stats_queue_msg_counts; +aggr_table(queue_stats, queue_msg_rates) -> + aggr_queue_stats_queue_msg_rates; +aggr_table(queue_stats, process_stats) -> + aggr_queue_stats_process_stats; +aggr_table(queue_exchange_stats, fine_stats) -> + aggr_queue_exchange_stats_fine_stats; +aggr_table(vhost_stats, deliver_get) -> + aggr_vhost_stats_deliver_get; +aggr_table(vhost_stats, fine_stats) -> + aggr_vhost_stats_fine_stats; +aggr_table(vhost_stats, queue_msg_rates) -> + aggr_vhost_stats_queue_msg_rates; +aggr_table(vhost_stats, queue_msg_counts) -> + aggr_vhost_stats_queue_msg_counts; +aggr_table(vhost_stats, coarse_conn_stats) -> + aggr_vhost_stats_coarse_conn_stats; +aggr_table(channel_queue_stats, deliver_get) -> + aggr_channel_queue_stats_deliver_get; +aggr_table(channel_queue_stats, fine_stats) -> + aggr_channel_queue_stats_fine_stats; +aggr_table(channel_queue_stats, queue_msg_counts) -> + aggr_channel_queue_stats_queue_msg_counts; +aggr_table(channel_stats, deliver_get) -> + aggr_channel_stats_deliver_get; +aggr_table(channel_stats, fine_stats) -> + aggr_channel_stats_fine_stats; +aggr_table(channel_stats, queue_msg_counts) -> + aggr_channel_stats_queue_msg_counts; +aggr_table(channel_stats, process_stats) -> + aggr_channel_stats_process_stats; +aggr_table(channel_exchange_stats, deliver_get) -> + aggr_channel_exchange_stats_deliver_get; +aggr_table(channel_exchange_stats, fine_stats) -> + aggr_channel_exchange_stats_fine_stats; +aggr_table(exchange_stats, fine_stats) -> + aggr_exchange_stats_fine_stats; +aggr_table(node_stats, coarse_node_stats) -> + aggr_node_stats_coarse_node_stats; +aggr_table(node_node_stats, coarse_node_node_stats) -> + aggr_node_node_stats_coarse_node_node_stats; +aggr_table(connection_stats, coarse_conn_stats) -> + aggr_connection_stats_coarse_conn_stats; +aggr_table(connection_stats, process_stats) -> + aggr_connection_stats_process_stats. + +-spec aggr_tables(event_type()) -> [{table_name(), type()}]. +aggr_tables(queue_stats) -> + [{aggr_queue_stats_fine_stats, fine_stats}, + {aggr_queue_stats_deliver_get, deliver_get}, + {aggr_queue_stats_queue_msg_counts, queue_msg_counts}, + {aggr_queue_stats_queue_msg_rates, queue_msg_rates}, + {aggr_queue_stats_process_stats, process_stats}]; +aggr_tables(queue_exchange_stats) -> + [{aggr_queue_exchange_stats_fine_stats, fine_stats}]; +aggr_tables(vhost_stats) -> + [{aggr_vhost_stats_deliver_get, deliver_get}, + {aggr_vhost_stats_fine_stats, fine_stats}, + {aggr_vhost_stats_queue_msg_rates, queue_msg_rates}, + {aggr_vhost_stats_queue_msg_counts, queue_msg_counts}, + {aggr_vhost_stats_coarse_conn_stats, coarse_conn_stats}]; +aggr_tables(channel_queue_stats) -> + [{aggr_channel_queue_stats_deliver_get, deliver_get}, + {aggr_channel_queue_stats_fine_stats, fine_stats}, + {aggr_channel_queue_stats_queue_msg_counts, queue_msg_counts}]; +aggr_tables(channel_stats) -> + [{aggr_channel_stats_deliver_get, deliver_get}, + {aggr_channel_stats_fine_stats, fine_stats}, + {aggr_channel_stats_queue_msg_counts, queue_msg_counts}, + {aggr_channel_stats_process_stats, process_stats}]; +aggr_tables(channel_exchange_stats) -> + [{aggr_channel_exchange_stats_deliver_get, deliver_get}, + {aggr_channel_exchange_stats_fine_stats, fine_stats}]; +aggr_tables(exchange_stats) -> + [{aggr_exchange_stats_fine_stats, fine_stats}]; +aggr_tables(node_stats) -> + [{aggr_node_stats_coarse_node_stats, coarse_node_stats}]; +aggr_tables(node_node_stats) -> + [{aggr_node_node_stats_coarse_node_node_stats, coarse_node_node_stats}]; +aggr_tables(connection_stats) -> + [{aggr_connection_stats_coarse_conn_stats, coarse_conn_stats}, + {aggr_connection_stats_process_stats, process_stats}]. + +-spec type_from_table(table_name()) -> type(). +type_from_table(aggr_queue_stats_deliver_get) -> + deliver_get; +type_from_table(aggr_queue_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_queue_stats_queue_msg_counts) -> + queue_msg_counts; +type_from_table(aggr_queue_stats_queue_msg_rates) -> + queue_msg_rates; +type_from_table(aggr_queue_stats_process_stats) -> + process_stats; +type_from_table(aggr_queue_exchange_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_vhost_stats_deliver_get) -> + deliver_get; +type_from_table(aggr_vhost_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_vhost_stats_queue_msg_rates) -> + queue_msg_rates; +type_from_table(aggr_vhost_stats_queue_msg_counts) -> + queue_msg_counts; +type_from_table(aggr_vhost_stats_coarse_conn_stats) -> + coarse_conn_stats; +type_from_table(aggr_channel_queue_stats_deliver_get) -> + deliver_get; +type_from_table(aggr_channel_queue_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_channel_queue_stats_queue_msg_counts) -> + queue_msg_counts; +type_from_table(aggr_channel_stats_deliver_get) -> + deliver_get; +type_from_table(aggr_channel_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_channel_stats_queue_msg_counts) -> + queue_msg_counts; +type_from_table(aggr_channel_stats_process_stats) -> + process_stats; +type_from_table(aggr_channel_exchange_stats_deliver_get) -> + deliver_get; +type_from_table(aggr_channel_exchange_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_exchange_stats_fine_stats) -> + fine_stats; +type_from_table(aggr_node_stats_coarse_node_stats) -> + coarse_node_stats; +type_from_table(aggr_node_node_stats_coarse_node_node_stats) -> + coarse_node_node_stats; +type_from_table(aggr_node_node_stats_coarse_conn_stats) -> + coarse_conn_stats; +type_from_table(aggr_connection_stats_coarse_conn_stats) -> + coarse_conn_stats; +type_from_table(aggr_connection_stats_process_stats) -> + process_stats. + +index(aggr_queue_stats_deliver_get) -> + aggr_queue_stats_deliver_get_index; +index(aggr_queue_stats_fine_stats) -> + aggr_queue_stats_fine_stats_index; +index(aggr_queue_stats_queue_msg_counts) -> + aggr_queue_stats_queue_msg_counts_index; +index(aggr_queue_stats_queue_msg_rates) -> + aggr_queue_stats_queue_msg_rates_index; +index(aggr_queue_stats_process_stats) -> + aggr_queue_stats_process_stats_index; +index(aggr_queue_exchange_stats_fine_stats) -> + aggr_queue_exchange_stats_fine_stats_index; +index(aggr_vhost_stats_deliver_get) -> + aggr_vhost_stats_deliver_get_index; +index(aggr_vhost_stats_fine_stats) -> + aggr_vhost_stats_fine_stats_index; +index(aggr_vhost_stats_queue_msg_rates) -> + aggr_vhost_stats_queue_msg_rates_index; +index(aggr_vhost_stats_queue_msg_counts) -> + aggr_vhost_stats_queue_msg_counts_index; +index(aggr_vhost_stats_coarse_conn_stats) -> + aggr_vhost_stats_coarse_conn_stats_index; +index(aggr_channel_queue_stats_deliver_get) -> + aggr_channel_queue_stats_deliver_get_index; +index(aggr_channel_queue_stats_fine_stats) -> + aggr_channel_queue_stats_fine_stats_index; +index(aggr_channel_queue_stats_queue_msg_counts) -> + aggr_channel_queue_stats_queue_msg_counts_index; +index(aggr_channel_stats_deliver_get) -> + aggr_channel_stats_deliver_get_index; +index(aggr_channel_stats_fine_stats) -> + aggr_channel_stats_fine_stats_index; +index(aggr_channel_stats_queue_msg_counts) -> + aggr_channel_stats_queue_msg_counts_index; +index(aggr_channel_stats_process_stats) -> + aggr_channel_stats_process_stats_index; +index(aggr_channel_exchange_stats_deliver_get) -> + aggr_channel_exchange_stats_deliver_get_index; +index(aggr_channel_exchange_stats_fine_stats) -> + aggr_channel_exchange_stats_fine_stats_index; +index(aggr_exchange_stats_fine_stats) -> + aggr_exchange_stats_fine_stats_index; +index(aggr_node_stats_coarse_node_stats) -> + aggr_node_stats_coarse_node_stats_index; +index(aggr_node_node_stats_coarse_node_node_stats) -> + aggr_node_node_stats_coarse_node_node_stats_index; +index(aggr_connection_stats_coarse_conn_stats) -> + aggr_connection_stats_coarse_conn_stats_index; +index(aggr_connection_stats_process_stats) -> + aggr_connection_stats_process_stats_index. + +key_index(connection_stats) -> + connection_stats_key_index; +key_index(channel_stats) -> + channel_stats_key_index; +key_index(aggr_queue_stats_deliver_get) -> + aggr_queue_stats_deliver_get_key_index; +key_index(aggr_queue_stats_fine_stats) -> + aggr_queue_stats_fine_stats_key_index; +key_index(aggr_queue_stats_queue_msg_counts) -> + aggr_queue_stats_queue_msg_counts_key_index; +key_index(aggr_queue_stats_queue_msg_rates) -> + aggr_queue_stats_queue_msg_rates_key_index; +key_index(aggr_queue_stats_process_stats) -> + aggr_queue_stats_process_stats_key_index; +key_index(aggr_queue_exchange_stats_fine_stats) -> + aggr_queue_exchange_stats_fine_stats_key_index; +key_index(aggr_vhost_stats_deliver_get) -> + aggr_vhost_stats_deliver_get_key_index; +key_index(aggr_vhost_stats_fine_stats) -> + aggr_vhost_stats_fine_stats_key_index; +key_index(aggr_vhost_stats_queue_msg_rates) -> + aggr_vhost_stats_queue_msg_rates_key_index; +key_index(aggr_vhost_stats_queue_msg_counts) -> + aggr_vhost_stats_queue_msg_counts_key_index; +key_index(aggr_vhost_stats_coarse_conn_stats) -> + aggr_vhost_stats_coarse_conn_stats_key_index; +key_index(aggr_channel_queue_stats_deliver_get) -> + aggr_channel_queue_stats_deliver_get_key_index; +key_index(aggr_channel_queue_stats_fine_stats) -> + aggr_channel_queue_stats_fine_stats_key_index; +key_index(aggr_channel_queue_stats_queue_msg_counts) -> + aggr_channel_queue_stats_queue_msg_counts_key_index; +key_index(aggr_channel_stats_deliver_get) -> + aggr_channel_stats_deliver_get_key_index; +key_index(aggr_channel_stats_fine_stats) -> + aggr_channel_stats_fine_stats_key_index; +key_index(aggr_channel_stats_queue_msg_counts) -> + aggr_channel_stats_queue_msg_counts_key_index; +key_index(aggr_channel_stats_process_stats) -> + aggr_channel_stats_process_stats_key_index; +key_index(aggr_channel_exchange_stats_deliver_get) -> + aggr_channel_exchange_stats_deliver_get_key_index; +key_index(aggr_channel_exchange_stats_fine_stats) -> + aggr_channel_exchange_stats_fine_stats_key_index; +key_index(aggr_exchange_stats_fine_stats) -> + aggr_exchange_stats_fine_stats_key_index; +key_index(aggr_node_stats_coarse_node_stats) -> + aggr_node_stats_coarse_node_stats_key_index; +key_index(aggr_node_node_stats_coarse_node_node_stats) -> + aggr_node_node_stats_coarse_node_node_stats_key_index; +key_index(aggr_connection_stats_coarse_conn_stats) -> + aggr_connection_stats_coarse_conn_stats_key_index; +key_index(aggr_connection_stats_process_stats) -> + aggr_connection_stats_process_stats_key_index. diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_sup.erl b/deps/rabbitmq_management/src/rabbit_mgmt_sup.erl new file mode 100644 index 0000000..326b65e --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_sup.erl @@ -0,0 +1,50 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Console. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_sup). + +-behaviour(mirrored_supervisor). + +-export([init/1]). +-export([start_link/0]). + +-include("rabbit_mgmt_metrics.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +init([]) -> + COLLECTOR = {rabbit_mgmt_event_collector, + {rabbit_mgmt_event_collector, start_link, []}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_event_collector]}, + CCOLLECTOR = {rabbit_mgmt_channel_stats_collector, + {rabbit_mgmt_channel_stats_collector, start_link, []}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_channel_stats_collector]}, + QCOLLECTOR = {rabbit_mgmt_queue_stats_collector, + {rabbit_mgmt_queue_stats_collector, start_link, []}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_queue_stats_collector]}, + GC = [{rabbit_mgmt_stats_gc:name(Table), {rabbit_mgmt_stats_gc, start_link, [Table]}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_stats_gc]} + || Table <- ?AGGR_TABLES], + ProcGC = [{rabbit_mgmt_stats_gc:name(Table), {rabbit_mgmt_stats_gc, start_link, [Table]}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_stats_gc]} + || Table <- ?PROC_STATS_TABLES], + DB = {rabbit_mgmt_db, {rabbit_mgmt_db, start_link, []}, + permanent, ?WORKER_WAIT, worker, [rabbit_mgmt_db]}, + {ok, {{one_for_one, 10, 10}, [COLLECTOR, CCOLLECTOR, QCOLLECTOR, DB] ++ GC ++ ProcGC}}. + +start_link() -> + mirrored_supervisor:start_link( + {local, ?MODULE}, ?MODULE, fun rabbit_misc:execute_mnesia_transaction/1, + ?MODULE, []). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_sup_sup.erl b/deps/rabbitmq_management/src/rabbit_mgmt_sup_sup.erl new file mode 100644 index 0000000..64f4674 --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_sup_sup.erl @@ -0,0 +1,71 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Console. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2011-2015 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_sup_sup). + +%% We want there to be one management database in the cluster, with a +%% globally registered name. So we use mirrored_supervisor for +%% failover (in rabbit_mgmt_sup) and register a global name for the +%% database. +%% +%% Unfortunately it's more complicated than using these things +%% naively. The first problem is that on failover the mirrored +%% supervisor might move the DB to a new node before the global name +%% database notices and removes the old record. In that case starting +%% the new database will fail. +%% +%% The second problem is that after a network partition things get +%% worse. Since mirrored_supervisor uses Mnesia for global shared +%% state, we have effectively two (or more) mirrored_supervisors. But +%% the global name database does not do this, so at least one of them +%% cannot start the management database; so the mirrored supervisor +%% has to die. But what if the admin restarts the partition which +%% contains the management DB? In that case we need to start a new +%% management DB in the winning partition. +%% +%% Rather than try to get mirrored_supervisor to handle this +%% post-partition state we go for a simpler approach: allow the whole +%% mirrored_supervisor to die in the two edge cases above, and +%% whenever we want to call into the mgmt DB we will start it up if it +%% appears not to be there. See rabbit_mgmt_db:safe_call/3 for the +%% code which restarts the DB if necessary. + +-behaviour(supervisor2). + +-export([start_link/0, start_child/0]). +-export([init/1]). + +-include_lib("rabbit_common/include/rabbit.hrl"). + +start_link() -> supervisor2:start_link({local, ?MODULE}, ?MODULE, []). + +start_child() -> supervisor2:start_child( ?MODULE, sup()). + +%%---------------------------------------------------------------------------- + +init([]) -> + %% see above as well as https://github.com/rabbitmq/rabbitmq-management/pull/84. + %% we sent a message to ourselves so that if there's a conflict + %% with the mirrored supervisor already being started on another node, + %% we fail and let the other node win in a way that doesn't + %% prevent rabbitmq_management and, in turn, the entire + %% node fail to start. + timer:apply_after(0, ?MODULE, start_child, []), + {ok, {{one_for_one, 0, 1}, []}}. + +sup() -> + {rabbit_mgmt_sup, {rabbit_mgmt_sup, start_link, []}, + temporary, ?SUPERVISOR_WAIT, supervisor, [rabbit_mgmt_sup]}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_util.erl b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl similarity index 66% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_util.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_util.erl index e3ea99a..939cf67 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_util.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_util). @@ -21,50 +21,39 @@ -export([is_authorized/2, is_authorized_admin/2, is_authorized_admin/4, vhost/1, vhost_from_headers/1]). -export([is_authorized_vhost/2, is_authorized_user/3, - is_authorized_monitor/2, is_authorized_policies/2, - is_authorized_global_parameters/2]). + is_authorized_monitor/2, is_authorized_policies/2]). -export([bad_request/3, bad_request_exception/4, id/2, parse_bool/1, parse_int/1]). -export([with_decode/4, not_found/3, amqp_request/4]). -export([with_channel/4, with_channel/5]). -export([props_to_method/2, props_to_method/4]). --export([all_or_one_vhost/2, http_to_amqp/5, reply/3, responder_map/1, - filter_vhost/3]). +-export([all_or_one_vhost/2, http_to_amqp/5, reply/3, filter_vhost/3]). -export([filter_conn_ch_list/3, filter_user/2, list_login_vhosts/2]). --export([with_decode/5, decode/1, decode/2, set_resp_header/3, +-export([with_decode/5, decode/1, decode/2, redirect/2, set_resp_header/3, args/1]). -export([reply_list/3, reply_list/5, reply_list/4, - sort_list/2, destination_type/1, reply_list_or_paginate/3 - ]). + sort_list/2, destination_type/1, reply_list_or_paginate/3]). -export([post_respond/1, columns/1, is_monitor/1]). -export([list_visible_vhosts/1, b64decode_or_throw/1, no_range/0, range/1, - range_ceil/1, floor/2, ceil/1, ceil/2]). --export([pagination_params/1, - maybe_filter_by_keyword/4, - get_value_param/2, - augment_resources/6 - ]). + range_ceil/1, floor/2, ceil/2]). +-export([pagination_params/1, maybe_filter_by_keyword/4, + get_value_param/2]). --import(rabbit_misc, [pget/2]). +-import(rabbit_misc, [pget/2, pget/3]). -include("rabbit_mgmt.hrl"). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-include_lib("webmachine/include/wm_reqdata.hrl"). +-include_lib("webmachine/include/wm_reqstate.hrl"). + -define(FRAMING, rabbit_framing_amqp_0_9_1). -define(DEFAULT_PAGE_SIZE, 100). -define(MAX_PAGE_SIZE, 500). - --define(MAX_RANGE, 500). - -record(pagination, {page = undefined, page_size = undefined, - name = undefined, use_regex = undefined}). + name = undefined, use_regex = undefined}). --record(aug_ctx, {req_data :: cowboy_req:req(), - pagination :: #pagination{}, - sort = [] :: [atom()], - columns = [] :: [atom()], - data :: term()}). +-define(MAX_RANGE, 500). %%-------------------------------------------------------------------- @@ -97,7 +86,7 @@ user_matches_vhost(ReqData, User) -> case vhost(ReqData) of not_found -> true; none -> true; - V -> lists:member(V, list_login_vhosts(User, cowboy_req:get(socket, ReqData))) + V -> lists:member(V, list_login_vhosts(User, peersock(ReqData))) end. %% Used for connections / channels. A normal user can only see / delete @@ -107,9 +96,9 @@ is_authorized_user(ReqData, Context, Item) -> is_authorized(ReqData, Context, <<"User not authorised to access object">>, fun(#user{username = Username, tags = Tags}) -> - case element(1, cowboy_req:method(ReqData)) of - <<"DELETE">> -> is_admin(Tags); - _ -> is_monitor(Tags) + case wrq:method(ReqData) of + 'DELETE' -> is_admin(Tags); + _ -> is_monitor(Tags) end orelse Username == pget(user, Item) end). @@ -123,28 +112,13 @@ is_authorized_policies(ReqData, Context) -> user_matches_vhost(ReqData, User) end). -%% For global parameters. Must be policymaker. -is_authorized_global_parameters(ReqData, Context) -> - is_authorized(ReqData, Context, - <<"User not authorised to access object">>, - fun(#user{tags = Tags}) -> - is_policymaker(Tags) - end). - is_authorized(ReqData, Context, ErrorMsg, Fun) -> - case cowboy_req:method(ReqData) of - {<<"OPTIONS">>, _} -> {true, ReqData, Context}; - _ -> is_authorized1(ReqData, Context, ErrorMsg, Fun) - end. - -is_authorized1(ReqData, Context, ErrorMsg, Fun) -> - case cowboy_req:parse_header(<<"authorization">>, ReqData) of - {ok, {<<"basic">>, {Username, Password}}, _} -> - is_authorized(ReqData, Context, - Username, Password, - ErrorMsg, Fun); + case rabbit_web_dispatch_util:parse_auth_header( + wrq:get_req_header("authorization", ReqData)) of + [Username, Password] -> + is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun); _ -> - {{false, ?AUTH_REALM}, ReqData, Context} + {?AUTH_REALM, ReqData, Context} end. is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun) -> @@ -159,7 +133,7 @@ is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun) -> end, case rabbit_access_control:check_user_login(Username, AuthProps) of {ok, User = #user{tags = Tags}} -> - {{IP, _}, _} = cowboy_req:peer(ReqData), + IP = peer(ReqData), case rabbit_access_control:check_user_loopback(Username, IP) of ok -> case is_mgmt_user(Tags) of @@ -182,12 +156,26 @@ is_authorized(ReqData, Context, Username, Password, ErrorMsg, Fun) -> not_authorised(<<"Login failed">>, ReqData, Context) end. +peer(ReqData) -> + {ok, {IP,_Port}} = peername(peersock(ReqData)), + IP. + +%% We can't use wrq:peer/1 because that trusts X-Forwarded-For. +peersock(ReqData) -> + WMState = ReqData#wm_reqdata.wm_state, + WMState#wm_reqstate.socket. + +%% Like the one in rabbit_net, but we and webmachine have a different +%% way of wrapping +peername(Sock) when is_port(Sock) -> inet:peername(Sock); +peername({ssl, SSL}) -> ssl:peername(SSL). + vhost_from_headers(ReqData) -> - case cowboy_req:header(<<"x-vhost">>, ReqData) of - {undefined, _} -> none; + case wrq:get_req_header(<<"x-vhost">>, ReqData) of + undefined -> none; %% blank x-vhost means "All hosts" is selected in the UI - {<<>>, _} -> none; - {VHost, _} -> VHost + [] -> none; + VHost -> list_to_binary(VHost) end. vhost(ReqData) -> @@ -205,32 +193,14 @@ destination_type(ReqData) -> <<"q">> -> queue end. -%% Provides a map of content type-to-responder that are supported by -%% reply/3. The map can be used in the content_types_provided/2 callback -%% used by cowboy_rest. Responder functions must be -%% exported from the caller module and must use reply/3 -%% under the hood. -responder_map(FunctionName) -> - [ - {<<"application/json">>, FunctionName}, - {<<"application/bert">>, FunctionName} - ]. - -reply({halt, _, _} = Reply, _ReqData, _Context) -> - Reply; reply(Facts, ReqData, Context) -> reply0(extract_columns(Facts, ReqData), ReqData, Context). reply0(Facts, ReqData, Context) -> - ReqData1 = set_resp_header(<<"Cache-Control">>, "no-cache", ReqData), + ReqData1 = set_resp_header("Cache-Control", "no-cache", ReqData), try - case cowboy_req:meta(media_type, ReqData1) of - {{<<"application">>, <<"bert">>, _}, _} -> - {term_to_binary(Facts), ReqData1, Context}; - _ -> - {mochijson2:encode(rabbit_mgmt_format:format_nulls(Facts)), - ReqData1, Context} - end + {mochijson2:encode(rabbit_mgmt_format:format_nulls(Facts)), ReqData1, + Context} catch exit:{json_encode, E} -> Error = iolist_to_binary( io_lib:format("JSON encode error: ~p", [E])), @@ -245,196 +215,58 @@ reply_list(Facts, ReqData, Context) -> reply_list(Facts, DefaultSorts, ReqData, Context) -> reply_list(Facts, DefaultSorts, ReqData, Context, undefined). -get_value_param(Name, ReqData) -> - case cowboy_req:qs_val(Name, ReqData) of - {undefined, _} -> undefined; - {Bin, _} -> binary_to_list(Bin) - end. reply_list(Facts, DefaultSorts, ReqData, Context, Pagination) -> SortList = - sort_list_and_paginate( + sort_list( extract_columns_list(Facts, ReqData), DefaultSorts, - get_value_param(<<"sort">>, ReqData), - get_sort_reverse(ReqData), Pagination), + wrq:get_qs_value("sort", ReqData), + wrq:get_qs_value("sort_reverse", ReqData), Pagination), reply(SortList, ReqData, Context). --spec get_sort_reverse(cowboy_req:req()) -> atom(). -get_sort_reverse(ReqData) -> - case get_value_param(<<"sort_reverse">>, ReqData) of - undefined -> false; - V -> list_to_atom(V) - end. - --spec is_pagination_requested(#pagination{} | undefined) -> boolean(). -is_pagination_requested(undefined) -> - false; -is_pagination_requested(#pagination{}) -> - true. - - -with_valid_pagination(ReqData, Context, Fun) -> +reply_list_or_paginate(Facts, ReqData, Context) -> try Pagination = pagination_params(ReqData), - Fun(Pagination) + reply_list(Facts, ["vhost", "name"], ReqData, Context, Pagination) catch error:badarg -> - Reason = iolist_to_binary( - io_lib:format("Pagination parameters are invalid", [])), - invalid_pagination(bad_request, Reason, ReqData, Context); - {error, ErrorType, S} -> + Reason = iolist_to_binary( + io_lib:format("Pagination parameters are invalid", [])), + invalid_pagination(bad_request, Reason, ReqData, Context); + {error, ErrorType, S} -> Reason = iolist_to_binary(S), invalid_pagination(ErrorType, Reason, ReqData, Context) end. -reply_list_or_paginate(Facts, ReqData, Context) -> - with_valid_pagination( - ReqData, Context, - fun(Pagination) -> - reply_list(Facts, ["vhost", "name"], ReqData, Context, Pagination) - end). - -merge_sorts(DefaultSorts, Extra) -> - case Extra of - undefined -> DefaultSorts; - Extra -> [Extra | DefaultSorts] - end. - -%% Resource augmentation. Works out the most optimal configuration of the operations: -%% sort, page, augment and executes it returning the result. -column_strategy(all, _) -> extended; -column_strategy(Cols, BasicColumns) -> - case Cols -- BasicColumns of - [] -> basic; - _ -> extended - end. - -% columns are [[binary()]] - this takes the first item -columns_as_strings(all) -> all; -columns_as_strings(Columns0) -> - [rabbit_data_coercion:to_list(C) || [C | _] <- Columns0]. - -augment_resources(Resources, DefaultSort, BasicColumns, ReqData, Context, - AugmentFun) -> - with_valid_pagination(ReqData, Context, - fun (Pagination) -> - augment_resources0(Resources, DefaultSort, - BasicColumns, Pagination, - ReqData, AugmentFun) - end). - -augment_resources0(Resources, DefaultSort, BasicColumns, Pagination, ReqData, - AugmentFun) -> - SortFun = fun (AugCtx) -> sort(DefaultSort, AugCtx) end, - AugFun = fun (AugCtx) -> augment(AugmentFun, AugCtx) end, - PageFun = fun page/1, - Pagination = pagination_params(ReqData), - Sort = def(get_value_param(<<"sort">>, ReqData), DefaultSort), - Columns = def(columns(ReqData), all), - ColumnsAsStrings = columns_as_strings(Columns), - Pipeline = - case {Pagination =/= undefined, - column_strategy(Sort, BasicColumns), - column_strategy(ColumnsAsStrings, BasicColumns)} of - {false, basic, basic} -> % no pagination, no extended fields - [SortFun]; - {false, _, _} -> - % no pagination, extended columns means we need to augment all - SLOW - [AugFun, SortFun]; - {true, basic, basic} -> - [SortFun, PageFun]; - {true, extended, _} -> - % pagination with extended sort columns - SLOW - [AugFun, SortFun, PageFun]; - {true, basic, extended} -> - % pagination with extended columns and sorting on basic - % here we can reduce the augementation set before - % augmenting - [SortFun, PageFun, AugFun] - end, - #aug_ctx{data = {_, Reply}} = run_augmentation( - #aug_ctx{req_data = ReqData, - pagination = Pagination, - sort = Sort, - columns = Columns, - data = {loaded, Resources}}, - Pipeline), - rabbit_mgmt_format:strip_pids(Reply). - -run_augmentation(C, []) -> C; -run_augmentation(C, [Next | Rem]) -> - C2 = Next(C), - run_augmentation(C2, Rem). - -sort(DefaultSort, Ctx = #aug_ctx{data = Data0, - req_data = ReqData, - sort = Sort}) -> - Data1 = get_data(Data0), - Data = sort_list(Data1, DefaultSort, Sort, - get_sort_reverse(ReqData)), - Ctx#aug_ctx{data = update_data(Data0, {sorted, Data})}. - -page(Ctx = #aug_ctx{data = Data0, - pagination = Pagination}) -> - Data = filter_and_paginate(get_data(Data0), Pagination), - Ctx#aug_ctx{data = update_data(Data0, {paged, Data})}. - -update_data({paged, Old}, New) -> - {paged, rabbit_misc:pset(items, get_data(New), Old)}; -update_data(_, New) -> - New. - -augment(AugmentFun, Ctx = #aug_ctx{data = Data0, req_data = ReqData}) -> - Data1 = get_data(Data0), - Data = AugmentFun(Data1, ReqData), - Ctx#aug_ctx{data = update_data(Data0, {augmented, Data})}. - -get_data({paged, Data}) -> - rabbit_misc:pget(items, Data); -get_data({_, Data}) -> - Data. - -%% XXX sort_list_and_paginate/2 is a more proper name for this function, keeping it -%% with this name for backwards compatibility --spec sort_list([Fact], [string()]) -> [Fact] when - Fact :: [{atom(), term()}]. -sort_list(Facts, Sorts) -> sort_list_and_paginate(Facts, Sorts, undefined, false, +sort_list(Facts, Sorts) -> sort_list(Facts, Sorts, undefined, false, undefined). --spec sort_list([Fact], [SortColumn], [SortColumn] | undefined, boolean()) -> [Fact] when - Fact :: [{atom(), term()}], - SortColumn :: string(). -sort_list(Facts, _, [], _) -> - %% Do not sort when we are explicitly requsted to sort with an - %% empty sort columns list. Note that this clause won't match when - %% 'sort' parameter is not provided in a HTTP request at all. - Facts; -sort_list(Facts, DefaultSorts, Sort, Reverse) -> - SortList = merge_sorts(DefaultSorts, Sort), +sort_list(Facts, DefaultSorts, Sort, Reverse, Pagination) -> + SortList = case Sort of + undefined -> DefaultSorts; + Extra -> [Extra | DefaultSorts] + end, %% lists:sort/2 is much more expensive than lists:sort/1 Sorted = [V || {_K, V} <- lists:sort( [{sort_key(F, SortList), F} || F <- Facts])], - maybe_reverse(Sorted, Reverse). - -sort_list_and_paginate(Facts, DefaultSorts, Sort, Reverse, Pagination) -> - filter_and_paginate(sort_list(Facts, DefaultSorts, Sort, Reverse), Pagination). -filter_and_paginate(Sorted, Pagination) -> ContextList = maybe_filter_context(Sorted, Pagination), - range_filter(ContextList, Pagination, Sorted). + range_filter(maybe_reverse(ContextList, Reverse), Pagination, Sorted). %% %% Filtering functions %% + + maybe_filter_context(List, #pagination{name = Name, use_regex = UseRegex}) when is_list(Name) -> lists:filter(fun(ListF) -> - maybe_filter_by_keyword(name, Name, ListF, UseRegex) - end, - List); + maybe_filter_by_keyword(name, Name, ListF, UseRegex) + end, + List); %% Here it is backward with the other API(s), that don't filter the data maybe_filter_context(List, _) -> List. @@ -460,25 +292,28 @@ maybe_filter_by_keyword(_, _, _, _) -> true. check_request_param(V, ReqData) -> - case cowboy_req:qs_val(V, ReqData) of - {undefined, _} -> undefined; - {Str, _} -> list_to_integer(binary_to_list(Str)) + case wrq:get_qs_value(V, ReqData) of + undefined -> undefined; + Str -> list_to_integer(Str) end. +get_value_param(V, ReqData) -> + wrq:get_qs_value(V, ReqData). + %% Validates and returns pagination parameters: %% Page is assumed to be > 0, PageSize > 0 PageSize <= ?MAX_PAGE_SIZE pagination_params(ReqData) -> - PageNum = check_request_param(<<"page">>, ReqData), - PageSize = check_request_param(<<"page_size">>, ReqData), - Name = get_value_param(<<"name">>, ReqData), - UseRegex = get_value_param(<<"use_regex">>, ReqData), + PageNum = check_request_param("page", ReqData), + PageSize = check_request_param("page_size", ReqData), + Name = get_value_param("name", ReqData), + UseRegex = get_value_param("use_regex", ReqData), case {PageNum, PageSize} of {undefined, _} -> undefined; - {PageNum, undefined} when is_integer(PageNum) andalso PageNum > 0 -> + {PageNum, undefined} when is_integer(PageNum) andalso PageNum > 0 -> #pagination{page = PageNum, page_size = ?DEFAULT_PAGE_SIZE, name = Name, use_regex = UseRegex}; - {PageNum, PageSize} when is_integer(PageNum) + {PageNum, PageSize} when is_integer(PageNum) andalso is_integer(PageSize) andalso (PageNum > 0) andalso (PageSize > 0) @@ -490,29 +325,30 @@ pagination_params(ReqData) -> [PageNum, PageSize])}) end. --spec maybe_reverse([any()], string() | true | false) -> [any()]. maybe_reverse([], _) -> []; +maybe_reverse(RangeList, "true") when is_list(RangeList) -> + lists:reverse(RangeList); maybe_reverse(RangeList, true) when is_list(RangeList) -> lists:reverse(RangeList); -maybe_reverse(RangeList, false) -> +maybe_reverse(RangeList, _) -> RangeList. %% for backwards compatibility, does not filter the list range_filter(List, undefined, _) -> List; -range_filter(List, RP = #pagination{page = PageNum, page_size = PageSize}, - TotalElements) -> +range_filter(List, RP = #pagination{page = PageNum, page_size = PageSize}, + TotalElements) -> Offset = (PageNum - 1) * PageSize + 1, try - range_response(lists:sublist(List, Offset, PageSize), RP, List, - TotalElements) + range_response(lists:sublist(List, Offset, PageSize), RP, List, + TotalElements) catch error:function_clause -> Reason = io_lib:format( - "Page out of range, page: ~p page size: ~p, len: ~p", - [PageNum, PageSize, length(List)]), + "Page out of range, page: ~p page size: ~p, len: ~p", + [PageNum, PageSize, length(List)]), throw({error, page_out_of_range, Reason}) end. @@ -563,29 +399,19 @@ pget_bin(Key, List, Default) -> {[{_K, V}], _} -> V; {[], _} -> Default end. -maybe_pagination(Item, false, ReqData) -> - extract_column_items(Item, columns(ReqData)); -maybe_pagination([{items, Item} | T], true, ReqData) -> - [{items, extract_column_items(Item, columns(ReqData))} | - maybe_pagination(T, true, ReqData)]; -maybe_pagination([H | T], true, ReqData) -> - [H | maybe_pagination(T,true, ReqData)]; -maybe_pagination(Item, true, ReqData) -> - [maybe_pagination(X, true, ReqData) || X <- Item]. extract_columns(Item, ReqData) -> - maybe_pagination(Item, is_pagination_requested(pagination_params(ReqData)), - ReqData). + extract_column_items(Item, columns(ReqData)). extract_columns_list(Items, ReqData) -> Cols = columns(ReqData), [extract_column_items(Item, Cols) || Item <- Items]. columns(ReqData) -> - case cowboy_req:qs_val(<<"columns">>, ReqData) of - {undefined, _} -> all; - {Bin, _} -> [[list_to_binary(T) || T <- string:tokens(C, ".")] - || C <- string:tokens(binary_to_list(Bin), ",")] + case wrq:get_qs_value("columns", ReqData) of + undefined -> all; + Str -> [[list_to_binary(T) || T <- string:tokens(C, ".")] + || C <- string:tokens(Str, ",")] end. extract_column_items(Item, all) -> @@ -600,7 +426,7 @@ extract_column_items(L, Cols) when is_list(L) -> extract_column_items(O, _Cols) -> O. -% want_column(_Col, all) -> true; +want_column(_Col, all) -> true; want_column(Col, Cols) -> lists:any(fun([C|_]) -> C == Col end, Cols). descend_columns(_K, []) -> []; @@ -630,10 +456,9 @@ invalid_pagination(Type,Reason, ReqData, Context) -> halt_response(Code, Type, Reason, ReqData, Context) -> Json = {struct, [{error, Type}, {reason, rabbit_mgmt_format:tuple(Reason)}]}, - {ok, ReqData1} = cowboy_req:reply(Code, - [{<<"content-type">>, <<"application/json">>}], - mochijson2:encode(Json), ReqData), - {halt, ReqData1, Context}. + ReqData1 = wrq:append_to_response_body(mochijson2:encode(Json), ReqData), + {{halt, Code}, set_resp_header( + "Content-Type", "application/json", ReqData1), Context}. id(Key, ReqData) when Key =:= exchange; Key =:= source; @@ -646,20 +471,19 @@ id(Key, ReqData) -> id0(Key, ReqData). id0(Key, ReqData) -> - case cowboy_req:binding(Key, ReqData) of - {undefined, _} -> none; - {Id, _} -> Id + case orddict:find(Key, wrq:path_info(ReqData)) of + {ok, Id} -> list_to_binary(mochiweb_util:unquote(Id)); + error -> none end. with_decode(Keys, ReqData, Context, Fun) -> - {ok, Body, ReqData1} = cowboy_req:body(ReqData), - with_decode(Keys, Body, ReqData1, Context, Fun). + with_decode(Keys, wrq:req_body(ReqData), ReqData, Context, Fun). with_decode(Keys, Body, ReqData, Context, Fun) -> case decode(Keys, Body) of {error, Reason} -> bad_request(Reason, ReqData, Context); {ok, Values, JSON} -> try - Fun(Values, JSON, ReqData) + Fun(Values, JSON) catch {error, Error} -> bad_request(Error, ReqData, Context) end @@ -697,8 +521,7 @@ http_to_amqp(MethodName, ReqData, Context, Transformers, Extra) -> not_found -> not_found(vhost_not_found, ReqData, Context); VHost -> - {ok, Body, ReqData1} = cowboy_req:body(ReqData), - case decode(Body) of + case decode(wrq:req_body(ReqData)) of {ok, Props} -> try Node = case pget(<<"node">>, Props) of @@ -706,15 +529,14 @@ http_to_amqp(MethodName, ReqData, Context, Transformers, Extra) -> N -> rabbit_nodes:make( binary_to_list(N)) end, - amqp_request(VHost, ReqData1, Context, Node, + amqp_request(VHost, ReqData, Context, Node, props_to_method( MethodName, Props, Transformers, Extra)) catch {error, Error} -> - bad_request(Error, ReqData1, Context) + bad_request(Error, ReqData, Context) end; {error, Reason} -> - bad_request(rabbit_mgmt_format:escape_html_tags(Reason), - ReqData1, Context) + bad_request(Reason, ReqData, Context) end end. @@ -802,8 +624,6 @@ with_channel(VHost, ReqData, end; {error, {auth_failure, Msg}} -> not_authorised(Msg, ReqData, Context); - {error, not_allowed} -> - not_authorised(<<"Access refused.">>, ReqData, Context); {error, access_refused} -> not_authorised(<<"Access refused.">>, ReqData, Context); {error, {nodedown, N}} -> @@ -818,14 +638,14 @@ bad_request_exception(Code, Reason, ReqData, Context) -> ReqData, Context). all_or_one_vhost(ReqData, Fun) -> - case vhost(ReqData) of + case rabbit_mgmt_util:vhost(ReqData) of none -> lists:append([Fun(V) || V <- rabbit_vhost:list()]); not_found -> vhost_not_found; VHost -> Fun(VHost) end. filter_vhost(List, ReqData, Context) -> - VHosts = list_login_vhosts(Context#context.user, cowboy_req:get(socket, ReqData)), + VHosts = list_login_vhosts(Context#context.user, peersock(ReqData)), [I || I <- List, lists:member(pget(vhost, I), VHosts)]. filter_user(List, _ReqData, #context{user = User}) -> @@ -845,8 +665,13 @@ filter_conn_ch_list(List, ReqData, Context) -> VHost -> [I || I <- List, pget(vhost, I) =:= VHost] end, ReqData, Context)). +redirect(Location, ReqData) -> + wrq:do_redirect(true, + set_resp_header("Location", + binary_to_list(Location), ReqData)). + set_resp_header(K, V, ReqData) -> - cowboy_req:set_resp_header(K, strip_crlf(V), ReqData). + wrq:set_resp_header(K, strip_crlf(V), ReqData). strip_crlf(Str) -> lists:append(string:tokens(Str, "\r\n")). @@ -856,12 +681,12 @@ args(L) -> rabbit_mgmt_format:to_amqp_table(L). %% Make replying to a post look like anything else... post_respond({true, ReqData, Context}) -> {true, ReqData, Context}; -post_respond({halt, ReqData, Context}) -> - {halt, ReqData, Context}; +post_respond({{halt, Code}, ReqData, Context}) -> + {{halt, Code}, ReqData, Context}; post_respond({JSON, ReqData, Context}) -> {true, set_resp_header( - <<"Content-Type">>, "application/json", - cowboy_req:set_resp_body(JSON, ReqData)), Context}. + "Content-Type", "application/json", + wrq:append_to_response_body(JSON, ReqData)), Context}. is_admin(T) -> intersects(T, [administrator]). is_policymaker(T) -> intersects(T, [administrator, policymaker]). @@ -958,23 +783,12 @@ ceil(TS, Interval) -> case floor(TS, Interval) of Floor -> Floor + Interval end. -ceil(X) when X < 0 -> - trunc(X); -ceil(X) -> - T = trunc(X), - case X - T == 0 of - true -> T; - false -> T + 1 - end. - int(Name, ReqData) -> - case cowboy_req:qs_val(list_to_binary(Name), ReqData) of - {undefined, _} -> undefined; - {Bin, _} -> case catch list_to_integer(binary_to_list(Bin)) of + case wrq:get_qs_value(Name, ReqData) of + undefined -> undefined; + Str -> case catch list_to_integer(Str) of {'EXIT', _} -> undefined; Integer -> Integer end end. -def(undefined, Def) -> Def; -def(V, _) -> V. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl similarity index 73% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl index 0059383..c019ea4 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_aliveness_test.erl @@ -11,32 +11,38 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_aliveness_test). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). -define(QUEUE, <<"aliveness-test">>). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_util:vhost(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl index f363d8c..5c533eb 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_binding.erl @@ -11,36 +11,40 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_binding). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, - is_authorized/2, allowed_methods/2, delete_resource/2]). --export([variances/2]). + is_authorized/2, allowed_methods/2, delete_resource/2, + args_hash/1]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> Binding = binding(ReqData), @@ -128,30 +132,15 @@ with_binding(ReqData, Context, Fun) -> Fun(Binding) end. -method(MethodName, #binding{source = #resource{name = S}, - destination = #resource{name = D}, - key = K, - args = A}) -> - case MethodName of - 'exchange.unbind' -> - #'exchange.unbind'{ - source = S, - destination = D, - routing_key = K, - arguments = A}; - 'queue.unbind' -> - #'queue.unbind'{ - queue = D, - exchange = S, - routing_key = K, - arguments = A} - end. - sync_resource(MethodName, ReqData, Context) -> with_binding( ReqData, Context, fun(Binding) -> - rabbit_mgmt_util:amqp_request( + Props0 = rabbit_mgmt_format:binding(Binding), + Props = Props0 ++ + [{exchange, proplists:get_value(source, Props0)}, + {queue, proplists:get_value(destination, Props0)}], + rabbit_mgmt_util:amqp_request( rabbit_mgmt_util:vhost(ReqData), ReqData, Context, - method(MethodName, Binding)) + rabbit_mgmt_util:props_to_method(MethodName, Props)) end). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl similarity index 71% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl index 2dabff5..887291a 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_bindings.erl @@ -11,57 +11,55 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_bindings). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([allowed_methods/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([allowed_methods/2, post_is_create/2, create_path/2]). -export([content_types_accepted/2, accept_content/2, resource_exists/2]). -export([basic/1, augmented/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init([Mode]) -> + {ok, {Mode, #context{}}}. -rest_init(Req, [Mode]) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), {Mode, #context{}}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. -%% The current version of Cowboy forces us to report the resource doesn't -%% exist here in order to get a 201 response. It seems Cowboy confuses the -%% resource from the request and the resource that will be created by POST. -%% https://github.com/ninenines/cowboy/issues/723#issuecomment-161319576 resource_exists(ReqData, {Mode, Context}) -> - case cowboy_req:method(ReqData) of - {<<"POST">>, _} -> - {false, ReqData, {Mode, Context}}; - _ -> - {case list_bindings(Mode, ReqData) of - vhost_not_found -> false; - _ -> true - end, ReqData, {Mode, Context}} - end. + {case list_bindings(Mode, ReqData) of + vhost_not_found -> false; + _ -> true + end, ReqData, {Mode, Context}}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, {Mode, Context}) -> {case Mode of - source_destination -> [<<"HEAD">>, <<"GET">>, <<"POST">>, <<"OPTIONS">>]; - _ -> [<<"HEAD">>, <<"GET">>, <<"OPTIONS">>] + source_destination -> ['HEAD', 'GET', 'POST', 'OPTIONS']; + _ -> ['HEAD', 'GET', 'OPTIONS'] end, ReqData, {Mode, Context}}. +post_is_create(ReqData, Context) -> + {true, ReqData, Context}. + to_json(ReqData, {Mode, Context}) -> Bs = [rabbit_mgmt_format:binding(B) || B <- list_bindings(Mode, ReqData)], rabbit_mgmt_util:reply_list( @@ -70,27 +68,30 @@ to_json(ReqData, {Mode, Context}) -> "routing_key", "properties_key"], ReqData, {Mode, Context}). -accept_content(ReqData0, {_Mode, Context}) -> - {ok, Body, ReqData} = cowboy_req:body(ReqData0), +create_path(ReqData, Context) -> + {"dummy", ReqData, Context}. + +accept_content(ReqData, {_Mode, Context}) -> Source = rabbit_mgmt_util:id(source, ReqData), Dest = rabbit_mgmt_util:id(destination, ReqData), DestType = rabbit_mgmt_util:id(dtype, ReqData), VHost = rabbit_mgmt_util:vhost(ReqData), - {ok, Props} = rabbit_mgmt_util:decode(Body), + {ok, Props} = rabbit_mgmt_util:decode(wrq:req_body(ReqData)), {Method, Key, Args} = method_key_args(DestType, Source, Dest, Props), Response = rabbit_mgmt_util:amqp_request(VHost, ReqData, Context, Method), case Response of - {halt, _, _} = Res -> + {{halt, _}, _, _} = Res -> Res; {true, ReqData, Context2} -> Loc = rabbit_web_dispatch_util:relativise( - binary_to_list(element(1, cowboy_req:path(ReqData))), + wrq:path(ReqData), binary_to_list( rabbit_mgmt_format:url( "/api/bindings/~s/e/~s/~s/~s/~s", [VHost, Source, DestType, Dest, rabbit_mgmt_format:pack_binding_props(Key, Args)]))), - {{true, Loc}, ReqData, Context2} + {true, rabbit_mgmt_util:set_resp_header("Location", Loc, ReqData), + Context2} end. is_authorized(ReqData, {Mode, Context}) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl similarity index 67% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl index 0fdb43f..e80769a 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channel.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_channel). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> case channel(ReqData) of @@ -43,10 +49,8 @@ resource_exists(ReqData, Context) -> end. to_json(ReqData, Context) -> - Payload = rabbit_mgmt_format:clean_consumer_details( - rabbit_mgmt_format:strip_pids(channel(ReqData))), rabbit_mgmt_util:reply( - {struct, Payload}, + {struct, rabbit_mgmt_format:strip_pids(channel(ReqData))}, ReqData, Context). is_authorized(ReqData, Context) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl similarity index 67% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl index 7a68d4a..15b33a6 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels.erl @@ -11,32 +11,38 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_channels). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, augmented/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> try diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl similarity index 71% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl index 985982b..357c2a6 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_channels_vhost.erl @@ -18,27 +18,33 @@ %% Lists channels in a vhost --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, augmented/2, resource_exists/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {rabbit_vhost:exists(rabbit_mgmt_util:id(vhost, ReqData)), ReqData, Context}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl similarity index 63% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl index 61da477..28ac785 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_cluster_name.erl @@ -11,37 +11,39 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_cluster_name). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {true, ReqData, Context}. @@ -50,18 +52,18 @@ to_json(ReqData, Context) -> rabbit_mgmt_util:reply( [{name, rabbit_nodes:cluster_name()}], ReqData, Context). -accept_content(ReqData0, Context) -> +accept_content(ReqData, Context) -> rabbit_mgmt_util:with_decode( - [name], ReqData0, Context, fun([Name], _, ReqData) -> + [name], ReqData, Context, fun([Name], _) -> rabbit_nodes:set_cluster_name( as_binary(Name)), {true, ReqData, Context} end). is_authorized(ReqData, Context) -> - case cowboy_req:method(ReqData) of - {<<"PUT">>, _} -> rabbit_mgmt_util:is_authorized_admin(ReqData, Context); - _ -> rabbit_mgmt_util:is_authorized(ReqData, Context) + case wrq:method(ReqData) of + 'PUT' -> rabbit_mgmt_util:is_authorized_admin(ReqData, Context); + _ -> rabbit_mgmt_util:is_authorized(ReqData, Context) end. as_binary(Val) when is_binary(Val) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl similarity index 71% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl index e90b3cb..dae78e8 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection.erl @@ -11,33 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connection). --export([init/3, rest_init/2, resource_exists/2, to_json/2, content_types_provided/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, is_authorized/2, allowed_methods/2, delete_resource/2, conn/1]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> case conn(ReqData) of @@ -52,9 +55,9 @@ to_json(ReqData, Context) -> delete_resource(ReqData, Context) -> Conn = conn(ReqData), Pid = proplists:get_value(pid, Conn), - Reason = case cowboy_req:header(<<"x-reason">>, ReqData) of - {undefined, _} -> "Closed via management plugin"; - {V, _} -> binary_to_list(V) + Reason = case wrq:get_req_header(<<"X-Reason">>, ReqData) of + undefined -> "Closed via management plugin"; + V -> V end, case proplists:get_value(type, Conn) of direct -> amqp_direct_connection:server_close(Pid, 320, Reason); diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl index 3d1fd4a..51b0b20 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connection_channels.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connection_channels). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> case rabbit_mgmt_wm_connection:conn(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl similarity index 67% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl index 87aaece..b118b6f 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections.erl @@ -11,32 +11,38 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_connections). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, augmented/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> try diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl index 358c28a..d158f4f 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_connections_vhost.erl @@ -18,27 +18,33 @@ %% Lists connections in a vhost --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, augmented/2, resource_exists/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {rabbit_vhost:exists(rabbit_mgmt_util:id(vhost, ReqData)), ReqData, Context}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl similarity index 57% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl index 1aace33..c36d0ac 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_consumers.erl @@ -11,49 +11,51 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -module(rabbit_mgmt_wm_consumers). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, resource_exists/2, +-export([init/1, to_json/2, content_types_provided/2, resource_exists/2, is_authorized/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_util:vhost(ReqData) of - not_found -> false; - none -> true; % none means `all` - _ -> true + vhost_not_found -> false; + _ -> true end, ReqData, Context}. to_json(ReqData, Context = #context{user = User}) -> - Arg = case rabbit_mgmt_util:vhost(ReqData) of - none -> all; - VHost -> VHost - end, - - Consumers = rabbit_mgmt_format:strip_pids(rabbit_mgmt_db:get_all_consumers(Arg)), - Formatted = [rabbit_mgmt_format:format_consumer_arguments(C) || C <- Consumers], + Consumers = case rabbit_mgmt_util:vhost(ReqData) of + none -> rabbit_mgmt_db:get_all_consumers(); + VHost -> rabbit_mgmt_db:get_all_consumers(VHost) + end, rabbit_mgmt_util:reply_list( - filter_user(Formatted, User), ReqData, Context). + filter_user(Consumers, User), ReqData, Context). is_authorized(ReqData, Context) -> rabbit_mgmt_util:is_authorized(ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl similarity index 62% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl index 48efde1..6d02f3e 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_definitions.erl @@ -11,50 +11,57 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_definitions). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). -export([content_types_accepted/2, allowed_methods/2, accept_json/2]). --export([accept_multipart/2]). --export([variances/2]). +-export([post_is_create/2, create_path/2, accept_multipart/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). -export([apply_defs/3]). -import(rabbit_misc, [pget/2, pget/3]). -include("rabbit_mgmt.hrl"). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{<<"application/json">>, accept_json}, - {{<<"multipart">>, <<"form-data">>, '*'}, accept_multipart}], ReqData, Context}. + {[{"application/json", accept_json}, + {"multipart/form-data", accept_multipart}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"POST">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'POST', 'OPTIONS'], ReqData, Context}. + +post_is_create(ReqData, Context) -> + {true, ReqData, Context}. + +create_path(ReqData, Context) -> + {"dummy", ReqData, Context}. to_json(ReqData, Context) -> case rabbit_mgmt_util:vhost(ReqData) of none -> all_definitions(ReqData, Context); not_found -> - rabbit_mgmt_util:bad_request(rabbit_data_coercion:to_binary("vhost_not_found"), + rabbit_mgmt_util:bad_request(list_to_binary("vhost_not_found"), ReqData, Context); _VHost -> vhost_definitions(ReqData, Context) @@ -70,23 +77,22 @@ all_definitions(ReqData, Context) -> export_binding(B, QNames)], {ok, Vsn} = application:get_key(rabbit, vsn), rabbit_mgmt_util:reply( - [{rabbit_version, rabbit_data_coercion:to_binary(Vsn)}] ++ + [{rabbit_version, list_to_binary(Vsn)}] ++ filter( - [{users, rabbit_mgmt_wm_users:users()}, - {vhosts, rabbit_mgmt_wm_vhosts:basic()}, - {permissions, rabbit_mgmt_wm_permissions:permissions()}, - {parameters, rabbit_mgmt_wm_parameters:basic(ReqData)}, - {global_parameters, rabbit_mgmt_wm_global_parameters:basic()}, - {policies, rabbit_mgmt_wm_policies:basic(ReqData)}, - {queues, Qs}, - {exchanges, Xs}, - {bindings, Bs}]), - case cowboy_req:qs_val(<<"download">>, ReqData) of - {undefined, _} -> ReqData; - {Filename, _} -> rabbit_mgmt_util:set_resp_header( - <<"Content-Disposition">>, + [{users, rabbit_mgmt_wm_users:users()}, + {vhosts, rabbit_mgmt_wm_vhosts:basic()}, + {permissions, rabbit_mgmt_wm_permissions:permissions()}, + {parameters, rabbit_mgmt_wm_parameters:basic(ReqData)}, + {policies, rabbit_mgmt_wm_policies:basic(ReqData)}, + {queues, Qs}, + {exchanges, Xs}, + {bindings, Bs}]), + case wrq:get_qs_value("download", ReqData) of + undefined -> ReqData; + Filename -> rabbit_mgmt_util:set_resp_header( + "Content-Disposition", "attachment; filename=" ++ - binary_to_list(Filename), ReqData) + mochiweb_util:unquote(Filename), ReqData) end, Context). @@ -101,40 +107,47 @@ vhost_definitions(ReqData, Context) -> export_binding(B, QNames)], {ok, Vsn} = application:get_key(rabbit, vsn), rabbit_mgmt_util:reply( - [{rabbit_version, rabbit_data_coercion:to_binary(Vsn)}] ++ + [{rabbit_version, list_to_binary(Vsn)}] ++ filter( [{policies, rabbit_mgmt_wm_policies:basic(ReqData)}, {queues, Qs}, {exchanges, Xs}, {bindings, Bs}]), - case cowboy_req:qs_val(<<"download">>, ReqData) of - {undefined, _} -> ReqData; - {Filename, _} -> rabbit_mgmt_util:set_resp_header( - <<"Content-Disposition">>, - "attachment; filename=" ++ - mochiweb_util:unquote(Filename), ReqData) + case wrq:get_qs_value("download", ReqData) of + undefined -> ReqData; + Filename -> rabbit_mgmt_util:set_resp_header( + "Content-Disposition", + "attachment; filename=" ++ + mochiweb_util:unquote(Filename), ReqData) end, Context). -accept_json(ReqData0, Context) -> - {ok, Body, ReqData} = cowboy_req:body(ReqData0), - accept(Body, ReqData, Context). +accept_json(ReqData, Context) -> + accept(wrq:req_body(ReqData), ReqData, Context). -accept_multipart(ReqData0, Context) -> - {Parts, ReqData} = get_all_parts(ReqData0), - Redirect = get_part(<<"redirect">>, Parts), - Json = get_part(<<"file">>, Parts), +accept_multipart(ReqData, Context) -> + Parts = webmachine_multipart:get_all_parts( + wrq:req_body(ReqData), + webmachine_multipart:find_boundary(ReqData)), + Redirect = get_part("redirect", Parts), + Json = get_part("file", Parts), Resp = {Res, _, _} = accept(Json, ReqData, Context), - case {Res, Redirect} of - {true, unknown} -> {true, ReqData, Context}; - {true, _} -> {{true, Redirect}, ReqData, Context}; - _ -> Resp + case Res of + true -> + ReqData1 = + case Redirect of + unknown -> ReqData; + _ -> rabbit_mgmt_util:redirect(Redirect, ReqData) + end, + {true, ReqData1, Context}; + _ -> + Resp end. is_authorized(ReqData, Context) -> - case cowboy_req:qs_val(<<"auth">>, ReqData) of - {undefined, _} -> rabbit_mgmt_util:is_authorized_admin(ReqData, Context); - {Auth, _} -> is_authorized_qs(ReqData, Context, Auth) + case wrq:get_qs_value("auth", ReqData) of + undefined -> rabbit_mgmt_util:is_authorized_admin(ReqData, Context); + Auth -> is_authorized_qs(ReqData, Context, Auth) end. %% Support for the web UI - it can't add a normal "authorization" @@ -154,7 +167,7 @@ accept(Body, ReqData, Context) -> apply_defs(Body, fun() -> {true, ReqData, Context} end, fun(E) -> rabbit_mgmt_util:bad_request(E, ReqData, Context) end); not_found -> - rabbit_mgmt_util:bad_request(rabbit_data_coercion:to_binary("vhost_not_found"), + rabbit_mgmt_util:bad_request(list_to_binary("vhost_not_found"), ReqData, Context); VHost -> apply_defs(Body, fun() -> {true, ReqData, Context} end, @@ -169,19 +182,18 @@ apply_defs(Body, SuccessFun, ErrorFun) -> {ok, _, All} -> Version = pget(rabbit_version, All), try - for_all(users, All, fun(User) -> - rabbit_mgmt_wm_user:put_user( - User, - Version) - end), - for_all(vhosts, All, fun add_vhost/1), - for_all(permissions, All, fun add_permission/1), - for_all(parameters, All, fun add_parameter/1), - for_all(global_parameters, All, fun add_global_parameter/1), - for_all(policies, All, fun add_policy/1), - for_all(queues, All, fun add_queue/1), - for_all(exchanges, All, fun add_exchange/1), - for_all(bindings, All, fun add_binding/1), + for_all(users, All, fun(User) -> + rabbit_mgmt_wm_user:put_user( + User, + Version) + end), + for_all(vhosts, All, fun add_vhost/1), + for_all(permissions, All, fun add_permission/1), + for_all(parameters, All, fun add_parameter/1), + for_all(policies, All, fun add_policy/1), + for_all(queues, All, fun add_queue/1), + for_all(exchanges, All, fun add_exchange/1), + for_all(bindings, All, fun add_binding/1), SuccessFun() catch {error, E} -> ErrorFun(format(E)); exit:E -> ErrorFun(format(E)) @@ -205,30 +217,16 @@ apply_defs(Body, SuccessFun, ErrorFun, VHost) -> end. format(#amqp_error{name = Name, explanation = Explanation}) -> - rabbit_data_coercion:to_binary(rabbit_misc:format("~s: ~s", [Name, Explanation])); + list_to_binary(rabbit_misc:format("~s: ~s", [Name, Explanation])); format(E) -> - rabbit_data_coercion:to_binary(rabbit_misc:format("~p", [E])). - -get_all_parts(ReqData) -> - get_all_parts(ReqData, []). - -get_all_parts(ReqData0, Acc) -> - case cowboy_req:part(ReqData0) of - {done, ReqData} -> - {Acc, ReqData}; - {ok, Headers, ReqData1} -> - Name = case cow_multipart:form_data(Headers) of - {data, N} -> N; - {file, N, _, _, _} -> N - end, - {ok, Body, ReqData} = cowboy_req:part_body(ReqData1), - get_all_parts(ReqData, [{Name, Body}|Acc]) - end. + list_to_binary(rabbit_misc:format("~p", [E])). get_part(Name, Parts) -> - case lists:keyfind(Name, 1, Parts) of - false -> unknown; - {_, Value} -> Value + %% TODO any reason not to use lists:keyfind instead? + Filtered = [Value || {N, _Meta, Value} <- Parts, N == Name], + case Filtered of + [] -> unknown; + [F] -> F end. export_queue(Queue) -> @@ -254,17 +252,16 @@ export_name(_Name) -> true. %%-------------------------------------------------------------------- rw_state() -> - [{users, [name, password_hash, hashing_algorithm, tags]}, - {vhosts, [name]}, - {permissions, [user, vhost, configure, write, read]}, - {parameters, [vhost, component, name, value]}, - {global_parameters, [name, value]}, - {policies, [vhost, name, pattern, definition, priority, 'apply-to']}, - {queues, [name, vhost, durable, auto_delete, arguments]}, - {exchanges, [name, vhost, type, durable, auto_delete, internal, - arguments]}, - {bindings, [source, vhost, destination, destination_type, routing_key, - arguments]}]. + [{users, [name, password_hash, hashing_algorithm, tags]}, + {vhosts, [name]}, + {permissions, [user, vhost, configure, write, read]}, + {parameters, [vhost, component, name, value]}, + {policies, [vhost, name, pattern, definition, priority, 'apply-to']}, + {queues, [name, vhost, durable, auto_delete, arguments]}, + {exchanges, [name, vhost, type, durable, auto_delete, internal, + arguments]}, + {bindings, [source, vhost, destination, destination_type, routing_key, + arguments]}]. filter(Items) -> [filter_items(N, V, proplists:get_value(N, rw_state())) || {N, V} <- Items]. @@ -283,20 +280,18 @@ strip_vhost(Item) -> for_all(Name, All, Fun) -> case pget(Name, All) of undefined -> ok; - List -> _ = [Fun([{atomise_name(K), V} || {K, V} <- I]) || - {struct, I} <- List], - ok + List -> [Fun([{atomise_name(K), V} || {K, V} <- I]) || + {struct, I} <- List] end. for_all(Name, All, VHost, Fun) -> case pget(Name, All) of undefined -> ok; - List -> _ = [Fun(VHost, [{atomise_name(K), V} || {K, V} <- I]) || - {struct, I} <- List], - ok + List -> [Fun(VHost, [{atomise_name(K), V} || {K, V} <- I]) || + {struct, I} <- List] end. -atomise_name(N) -> rabbit_data_coercion:to_atom(N). +atomise_name(N) -> list_to_atom(binary_to_list(N)). %%-------------------------------------------------------------------- @@ -307,15 +302,11 @@ add_parameter(Param) -> Term = rabbit_misc:json_to_term(pget(value, Param)), case rabbit_runtime_parameters:set(VHost, Comp, Key, Term, none) of ok -> ok; - {error_string, E} -> S = rabbit_misc:format(" (~s/~s/~s)", [VHost, Comp, Key]), - exit(rabbit_data_coercion:to_binary(rabbit_mgmt_format:escape_html_tags(E ++ S))) + {error_string, E} -> S = rabbit_misc:format(" (~s/~s/~s)", + [VHost, Comp, Key]), + exit(list_to_binary(E ++ S)) end. -add_global_parameter(Param) -> - Key = pget(name, Param), - Term = rabbit_misc:json_to_term(pget(value, Param)), - rabbit_runtime_parameters:set_global(Key, Term). - add_policy(Param) -> VHost = pget(vhost, Param), add_policy(VHost, Param). @@ -329,7 +320,7 @@ add_policy(VHost, Param) -> pget('apply-to', Param, <<"all">>)) of ok -> ok; {error_string, E} -> S = rabbit_misc:format(" (~s/~s)", [VHost, Key]), - exit(rabbit_data_coercion:to_binary(rabbit_mgmt_format:escape_html_tags(E ++ S))) + exit(list_to_binary(E ++ S)) end. add_vhost(VHost) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl index be7b032..7f7ba76 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange.erl @@ -11,38 +11,40 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_exchange). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2, exchange/1, exchange/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {case exchange(ReqData) of @@ -54,7 +56,7 @@ to_json(ReqData, Context) -> try [X] = rabbit_mgmt_db:augment_exchanges( [exchange(ReqData)], rabbit_mgmt_util:range(ReqData), full), - rabbit_mgmt_util:reply(rabbit_mgmt_format:strip_pids(X), ReqData, Context) + rabbit_mgmt_util:reply(X, ReqData, Context) catch {error, invalid_range_parameters, Reason} -> rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) @@ -67,7 +69,7 @@ accept_content(ReqData, Context) -> [{exchange, rabbit_mgmt_util:id(exchange, ReqData)}]). delete_resource(ReqData, Context) -> - IfUnused = <<"true">> =:= element(1, cowboy_req:qs_val(<<"if-unused">>, ReqData)), + IfUnused = "true" =:= wrq:get_qs_value("if-unused", ReqData), rabbit_mgmt_util:amqp_request( rabbit_mgmt_util:vhost(ReqData), ReqData, Context, #'exchange.delete'{exchange = id(ReqData), diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl similarity index 78% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl index 76a9d26..ff2dbb1 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchange_publish.erl @@ -16,29 +16,30 @@ -module(rabbit_mgmt_wm_exchange_publish). --export([init/3, rest_init/2, resource_exists/2, is_authorized/2, - allowed_methods/2, content_types_provided/2, accept_content/2, - content_types_accepted/2]). --export([variances/2]). +-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2, + allowed_methods/2, content_types_provided/2, process_post/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. allowed_methods(ReqData, Context) -> - {[<<"POST">>, <<"OPTIONS">>], ReqData, Context}. + {['POST', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_wm_exchange:exchange(ReqData) of @@ -46,18 +47,18 @@ resource_exists(ReqData, Context) -> _ -> true end, ReqData, Context}. -content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. +post_is_create(ReqData, Context) -> + {false, ReqData, Context}. -accept_content(ReqData, Context) -> +process_post(ReqData, Context) -> rabbit_mgmt_util:post_respond(do_it(ReqData, Context)). -do_it(ReqData0, Context) -> - VHost = rabbit_mgmt_util:vhost(ReqData0), - X = rabbit_mgmt_util:id(exchange, ReqData0), +do_it(ReqData, Context) -> + VHost = rabbit_mgmt_util:vhost(ReqData), + X = rabbit_mgmt_util:id(exchange, ReqData), rabbit_mgmt_util:with_decode( - [routing_key, properties, payload, payload_encoding], ReqData0, Context, - fun ([RoutingKey, Props0, Payload0, Enc], _, ReqData) when is_binary(Payload0) -> + [routing_key, properties, payload, payload_encoding], ReqData, Context, + fun ([RoutingKey, Props0, Payload0, Enc], _) when is_binary(Payload0) -> rabbit_mgmt_util:with_channel( VHost, ReqData, Context, fun (Ch) -> @@ -85,7 +86,7 @@ do_it(ReqData0, Context) -> bad(Err, ReqData, Context) end end); - ([_RoutingKey, _Props, _Payload, _Enc], _, _ReqData) -> + ([_RoutingKey, _Props, _Payload, _Enc], _) -> throw({error, payload_not_string}) end). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl similarity index 58% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl index 170ee1b..529acbc 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_exchanges.erl @@ -11,35 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_exchanges). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, resource_exists/2, basic/1, augmented/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). --define(DEFAULT_SORT, ["vhost", "name"]). - --define(BASIC_COLUMNS, ["vhost", "name", "type", "durable", "auto_delete", - "internal", "arguments", "pid"]). - %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case exchanges0(ReqData) of @@ -49,12 +50,8 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> try - Basic = rabbit_mgmt_util:filter_vhost(basic(ReqData), ReqData, - Context), - Data = rabbit_mgmt_util:augment_resources(Basic, ?DEFAULT_SORT, - ?BASIC_COLUMNS, ReqData, - Context, fun augment/2), - rabbit_mgmt_util:reply(Data, ReqData, Context) + rabbit_mgmt_util:reply_list_or_paginate(augmented(ReqData, Context), + ReqData, Context) catch {error, invalid_range_parameters, Reason} -> rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) @@ -65,10 +62,6 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- -augment(Basic, ReqData) -> - rabbit_mgmt_db:augment_exchanges(Basic, rabbit_mgmt_util:range(ReqData), - basic). - augmented(ReqData, Context) -> rabbit_mgmt_db:augment_exchanges( rabbit_mgmt_util:filter_vhost(basic(ReqData), ReqData, Context), diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl similarity index 64% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl index 4e1d70a..5de1b16 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_extensions.erl @@ -16,24 +16,29 @@ -module(rabbit_mgmt_wm_extensions). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([variances/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> Modules = rabbit_mgmt_dispatcher:modules([]), diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl similarity index 52% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl index 70407b9..eb71a3f 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_healthchecks.erl @@ -11,28 +11,34 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_healthchecks). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case node0(ReqData) of @@ -42,26 +48,20 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> Node = node0(ReqData), - Timeout = case cowboy_req:header(<<"timeout">>, ReqData) of - {undefined, _} -> 70000; - {Val, _} -> list_to_integer(binary_to_list(Val)) - end, - case rabbit_health_check:node(Node, Timeout) of - ok -> - rabbit_mgmt_util:reply([{status, ok}], ReqData, Context); - {badrpc, Err} -> - failure(rabbit_mgmt_format:print("~p", Err), ReqData, Context); - {error_string, Err} -> - S = rabbit_mgmt_format:escape_html_tags( - rabbit_data_coercion:to_list(rabbit_mgmt_format:print(Err))), - failure(S, ReqData, Context) + try + Timeout = case wrq:get_req_header("timeout", ReqData) of + undefined -> 70000; + Val -> list_to_integer(Val) + end, + rabbit_health_check:node(Node, Timeout), + rabbit_mgmt_util:reply([{status, ok}], ReqData, Context) + catch + {node_is_ko, ErrorMsg, _ErrorCode} -> + rabbit_mgmt_util:reply([{status, failed}, + {reason, rabbit_mgmt_format:print(ErrorMsg)}], + ReqData, Context) end. -failure(Message, ReqData, Context) -> - rabbit_mgmt_util:reply([{status, failed}, - {reason, Message}], - ReqData, Context). - is_authorized(ReqData, Context) -> rabbit_mgmt_util:is_authorized(ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl similarity index 69% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl index dfad459..1bc41f3 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_node). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case node0(ReqData) of @@ -63,8 +69,8 @@ augment(ReqData, Node, Data) -> Data, [memory, binary]). augment(Key, ReqData, Node, Data) -> - case cowboy_req:qs_val(list_to_binary(atom_to_list(Key)), ReqData) of - {<<"true">>, _} -> Res = case rpc:call(Node, rabbit_vm, Key, [], infinity) of + case wrq:get_qs_value(atom_to_list(Key), ReqData) of + "true" -> Res = case rpc:call(Node, rabbit_vm, Key, [], infinity) of {badrpc, _} -> not_available; Result -> Result end, diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl similarity index 70% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl index 3b3ccaf..37ed784 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory.erl @@ -11,29 +11,36 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_node_memory). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init([Mode]) -> {ok, {Mode, #context{}}}. -rest_init(Req, [Mode]) -> {ok, Req, {Mode, #context{}}}. +finish_request(ReqData, {Mode, Context}) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), {Mode, Context}}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {node_exists(ReqData, get_node(ReqData)), ReqData, Context}. @@ -71,7 +78,9 @@ augment(Mode, ReqData) -> format(absolute, Result) -> Result; format(relative, Result) -> - {value, {total, Total}, Rest} = lists:keytake(total, 1, Result), + {[{total, Total}], Rest} = lists:splitwith(fun({Key, _}) -> + Key == total + end, Result), [{total, 100} | [{K, percentage(V, Total)} || {K, V} <- Rest]]. percentage(Part, Total) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl similarity index 77% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl index 000c485..e7ce6dd 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_node_memory_ets.erl @@ -11,29 +11,36 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_node_memory_ets). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([resource_exists/2]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init([Mode]) -> {ok, {Mode, #context{}}}. -rest_init(Req, [Mode]) -> {ok, Req, {Mode, #context{}}}. +finish_request(ReqData, {Mode, Context}) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), {Mode, Context}}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {node_exists(ReqData, get_node(ReqData)), ReqData, Context}. @@ -52,7 +59,7 @@ get_node(ReqData) -> get_filter(ReqData) -> case rabbit_mgmt_util:id(filter, ReqData) of none -> all; - <<"management">> -> rabbit_mgmt_storage; + <<"management">> -> rabbit_mgmt_event_collector; Other when is_binary(Other) -> list_to_atom(binary_to_list(Other)); _ -> all end. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl similarity index 71% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl index 5031aaa..e1cbf08 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_nodes.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_nodes). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). -export([all_nodes/1, all_nodes_raw/0]). --export([variances/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> try diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl index d2257f4..fe36948 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_overview.erl @@ -11,34 +11,40 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_overview). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([variances/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2, pget/3]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, ?MODULE), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context = #context{user = User = #user{tags = Tags}}) -> - RatesMode = rabbit_mgmt_agent_config:get_env(rates_mode), + {ok, RatesMode} = application:get_env(rabbitmq_management, rates_mode), %% NB: this duplicates what's in /nodes but we want a global idea %% of this. And /nodes is not accessible to non-monitor users. ExchangeTypes = rabbit_mgmt_external_stats:list_registry_plugins(exchange), @@ -58,6 +64,7 @@ to_json(ReqData, Context = #context{user = User = #user{tags = Tags}}) -> [{K, maybe_struct(V)} || {K,V} <- rabbit_mgmt_db:get_overview(Range)] ++ [{node, node()}, + {statistics_db_node, stats_db_node()}, {listeners, listeners()}, {contexts, web_contexts(ReqData)}]; _ -> @@ -76,6 +83,12 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- +stats_db_node() -> + case global:whereis_name(rabbit_mgmt_db) of + undefined -> not_running; + Pid -> node(Pid) + end. + version(App) -> {ok, V} = application:get_key(App, vsn), list_to_binary(V). @@ -97,11 +110,8 @@ web_contexts(ReqData) -> [fmt_contexts(N) || N <- rabbit_mgmt_wm_nodes:all_nodes(ReqData)]), ["description", "port", "node"]). -fmt_contexts(Node) -> - [fmt_context(Node, C) || C <- pget(contexts, Node, [])]. - -fmt_context(Node, C) -> - rabbit_mgmt_format:web_context([{node, pget(name, Node)} | C]). +fmt_contexts(N) -> + [[{node, pget(name, N)} | C] || C <- pget(contexts, N, [])]. erlang_version() -> list_to_binary(rabbit_misc:otp_release()). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl similarity index 69% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl index 049e4f1..a72693a 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameter.erl @@ -11,38 +11,43 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_parameter). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-import(rabbit_misc, [pget/2]). + +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +init(_Config) -> {ok, #context{}}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {case parameter(ReqData) of @@ -55,24 +60,22 @@ to_json(ReqData, Context) -> rabbit_mgmt_wm_parameters:fix_shovel_publish_properties(parameter(ReqData))), ReqData, Context). -accept_content(ReqData0, Context = #context{user = User}) -> - case rabbit_mgmt_util:vhost(ReqData0) of +accept_content(ReqData, Context = #context{user = User}) -> + case rabbit_mgmt_util:vhost(ReqData) of not_found -> - rabbit_mgmt_util:not_found(vhost_not_found, ReqData0, Context); + rabbit_mgmt_util:not_found(vhost_not_found, ReqData, Context); VHost -> rabbit_mgmt_util:with_decode( - [value], ReqData0, Context, - fun([Value], _, ReqData) -> + [value], ReqData, Context, + fun([Value], _) -> case rabbit_runtime_parameters:set( VHost, component(ReqData), name(ReqData), rabbit_misc:json_to_term(Value), User) of ok -> {true, ReqData, Context}; {error_string, Reason} -> - S = rabbit_mgmt_format:escape_html_tags( - rabbit_data_coercion:to_list(Reason)), rabbit_mgmt_util:bad_request( - rabbit_data_coercion:to_binary(S), ReqData, Context) + list_to_binary(Reason), ReqData, Context) end end) end. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl similarity index 79% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl index a488449..696879d 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_parameters.erl @@ -11,31 +11,37 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_parameters). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, resource_exists/2, basic/1]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([fix_shovel_publish_properties/1]). --export([variances/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case basic(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl index be83f8f..21cc294 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permission.erl @@ -11,38 +11,40 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permission). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {case perms(ReqData) of @@ -54,17 +56,17 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> rabbit_mgmt_util:reply(perms(ReqData), ReqData, Context). -accept_content(ReqData0, Context) -> - case perms(ReqData0) of +accept_content(ReqData, Context) -> + case perms(ReqData) of not_found -> rabbit_mgmt_util:bad_request(vhost_or_user_not_found, - ReqData0, Context); + ReqData, Context); _ -> - User = rabbit_mgmt_util:id(user, ReqData0), - VHost = rabbit_mgmt_util:id(vhost, ReqData0), + User = rabbit_mgmt_util:id(user, ReqData), + VHost = rabbit_mgmt_util:id(vhost, ReqData), rabbit_mgmt_util:with_decode( - [configure, write, read], ReqData0, Context, - fun([Conf, Write, Read], _, ReqData) -> + [configure, write, read], ReqData, Context, + fun([Conf, Write, Read], _) -> rabbit_auth_backend_internal:set_permissions( User, VHost, Conf, Write, Read), {true, ReqData, Context} diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl similarity index 63% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl index 590c6b9..46ad475 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). -export([permissions/0]). --export([variances/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> rabbit_mgmt_util:reply_list(permissions(), ["vhost", "user"], diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl similarity index 66% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl index dc3438e..bcf8d38 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_user.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions_user). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, resource_exists/2, +-export([init/1, to_json/2, content_types_provided/2, resource_exists/2, is_authorized/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_wm_user:user(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl similarity index 65% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl index 7d22f20..ba220b8 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_permissions_vhost.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_permissions_vhost). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, resource_exists/2, +-export([init/1, to_json/2, content_types_provided/2, resource_exists/2, is_authorized/2]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {rabbit_vhost:exists(rabbit_mgmt_wm_vhost:id(ReqData)), ReqData, Context}. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl similarity index 68% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl index b971d6d..e510745 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_policies.erl @@ -11,30 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_policies). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, resource_exists/2, basic/1]). --export([variances/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case basic(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl similarity index 69% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl index 1b25416..3460a87 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_policy.erl @@ -11,38 +11,43 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_policy). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-import(rabbit_misc, [pget/2]). + +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +init(_Config) -> {ok, #context{}}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {case policy(ReqData) of @@ -53,14 +58,14 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> rabbit_mgmt_util:reply(policy(ReqData), ReqData, Context). -accept_content(ReqData0, Context) -> - case rabbit_mgmt_util:vhost(ReqData0) of +accept_content(ReqData, Context) -> + case rabbit_mgmt_util:vhost(ReqData) of not_found -> - rabbit_mgmt_util:not_found(vhost_not_found, ReqData0, Context); + rabbit_mgmt_util:not_found(vhost_not_found, ReqData, Context); VHost -> rabbit_mgmt_util:with_decode( - [pattern, definition], ReqData0, Context, - fun([Pattern, Definition], Body, ReqData) -> + [pattern, definition], ReqData, Context, + fun([Pattern, Definition], Body) -> case rabbit_policy:set( VHost, name(ReqData), Pattern, rabbit_misc:json_to_term(Definition), @@ -70,7 +75,7 @@ accept_content(ReqData0, Context) -> {true, ReqData, Context}; {error_string, Reason} -> rabbit_mgmt_util:bad_request( - rabbit_mgmt_format:escape_html_tags(Reason), ReqData, Context) + list_to_binary(Reason), ReqData, Context) end end) end. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl similarity index 61% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl index 8322831..d1e87a5 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue.erl @@ -11,38 +11,40 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queue). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2, queue/1, queue/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {case queue(ReqData) of @@ -53,11 +55,8 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> try [Q] = rabbit_mgmt_db:augment_queues( - [queue(ReqData)], rabbit_mgmt_util:range_ceil(ReqData), - full), - Payload = rabbit_mgmt_format:clean_consumer_details( - rabbit_mgmt_format:strip_pids(Q)), - rabbit_mgmt_util:reply(ensure_defaults(Payload), ReqData, Context) + [queue(ReqData)], rabbit_mgmt_util:range_ceil(ReqData), full), + rabbit_mgmt_util:reply(rabbit_mgmt_format:strip_pids(Q), ReqData, Context) catch {error, invalid_range_parameters, Reason} -> rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) @@ -82,21 +81,6 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- -%% this is here to ensure certain data points are always there. When a queue -%% is moved there can be transient periods where certain advanced metrics aren't -%% yet available on the new node. -ensure_defaults(Payload0) -> - case lists:keyfind(garbage_collection, 1, Payload0) of - {_K, _V} -> Payload0; - false -> - [{garbage_collection, - [{max_heap_size,-1}, - {min_bin_vheap_size,-1}, - {min_heap_size,-1}, - {fullsweep_after,-1}, - {minor_gcs,-1}]} | Payload0] - end. - queue(ReqData) -> case rabbit_mgmt_util:vhost(ReqData) of not_found -> not_found; @@ -111,5 +95,4 @@ queue(VHost, QName) -> {error, not_found} -> not_found end. -qs_true(Key, ReqData) -> - <<"true">> =:= element(1, cowboy_req:qs_val(list_to_binary(Key), ReqData)). +qs_true(Key, ReqData) -> "true" =:= wrq:get_qs_value(Key, ReqData). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl similarity index 67% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl index e84932b..b75e2dc 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_actions.erl @@ -16,25 +16,28 @@ -module(rabbit_mgmt_wm_queue_actions). --export([init/3, rest_init/2, resource_exists/2, is_authorized/2, - allowed_methods/2, content_types_accepted/2, accept_content/2]). --export([variances/2]). +-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2, + allowed_methods/2, process_post/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. allowed_methods(ReqData, Context) -> - {[<<"POST">>, <<"OPTIONS">>], ReqData, Context}. + {['POST', 'OPTIONS'], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_wm_queue:queue(ReqData) of @@ -42,18 +45,18 @@ resource_exists(ReqData, Context) -> _ -> true end, ReqData, Context}. -content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. +post_is_create(ReqData, Context) -> + {false, ReqData, Context}. -accept_content(ReqData, Context) -> +process_post(ReqData, Context) -> rabbit_mgmt_util:post_respond(do_it(ReqData, Context)). -do_it(ReqData0, Context) -> - VHost = rabbit_mgmt_util:vhost(ReqData0), - QName = rabbit_mgmt_util:id(queue, ReqData0), +do_it(ReqData, Context) -> + VHost = rabbit_mgmt_util:vhost(ReqData), + QName = rabbit_mgmt_util:id(queue, ReqData), rabbit_mgmt_util:with_decode( - [action], ReqData0, Context, - fun([Action], _Body, ReqData) -> + [action], ReqData, Context, + fun([Action], _Body) -> rabbit_amqqueue:with( rabbit_misc:r(VHost, queue, QName), fun(Q) -> action(Action, Q, ReqData, Context) end) @@ -69,7 +72,7 @@ action(<<"sync">>, #amqqueue{pid = QPid}, ReqData, Context) -> {true, ReqData, Context}; action(<<"cancel_sync">>, #amqqueue{pid = QPid}, ReqData, Context) -> - _ = rabbit_amqqueue:cancel_sync_mirrors(QPid), + rabbit_amqqueue:cancel_sync_mirrors(QPid), {true, ReqData, Context}; action(Else, _Q, ReqData, Context) -> diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl index 2c69a5b..85cd5c8 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_get.erl @@ -16,29 +16,31 @@ -module(rabbit_mgmt_wm_queue_get). --export([init/3, rest_init/2, resource_exists/2, is_authorized/2, - allowed_methods/2, accept_content/2, content_types_provided/2, - content_types_accepted/2]). --export([variances/2]). +-export([init/1, resource_exists/2, post_is_create/2, is_authorized/2, + allowed_methods/2, process_post/2, content_types_provided/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. allowed_methods(ReqData, Context) -> - {[<<"POST">>, <<"OPTIONS">>], ReqData, Context}. + {['POST', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_wm_queue:queue(ReqData) of @@ -46,18 +48,18 @@ resource_exists(ReqData, Context) -> _ -> true end, ReqData, Context}. -content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. +post_is_create(ReqData, Context) -> + {false, ReqData, Context}. -accept_content(ReqData, Context) -> +process_post(ReqData, Context) -> rabbit_mgmt_util:post_respond(do_it(ReqData, Context)). -do_it(ReqData0, Context) -> - VHost = rabbit_mgmt_util:vhost(ReqData0), - Q = rabbit_mgmt_util:id(queue, ReqData0), +do_it(ReqData, Context) -> + VHost = rabbit_mgmt_util:vhost(ReqData), + Q = rabbit_mgmt_util:id(queue, ReqData), rabbit_mgmt_util:with_decode( - [requeue, count, encoding], ReqData0, Context, - fun([RequeueBin, CountBin, EncBin], Body, ReqData) -> + [requeue, count, encoding], ReqData, Context, + fun([RequeueBin, CountBin, EncBin], Body) -> rabbit_mgmt_util:with_channel( VHost, ReqData, Context, fun (Ch) -> @@ -66,7 +68,9 @@ do_it(ReqData0, Context) -> Enc = case EncBin of <<"auto">> -> auto; <<"base64">> -> base64; - _ -> throw({error, <<"Unsupported encoding. Please use auto or base64.">>}) + _ -> throw({error, + {bad_encoding, + EncBin}}) end, Trunc = case proplists:get_value(truncate, Body) of undefined -> none; @@ -122,7 +126,7 @@ payload_part(Payload, Enc) -> {PL, E} = case Enc of auto -> try %% TODO mochijson does this but is it safe? - _ = xmerl_ucs:from_utf8(Payload), + xmerl_ucs:from_utf8(Payload), {Payload, string} catch exit:{ucs, _} -> {base64:encode(Payload), base64} diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl similarity index 69% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl index a778d25..b4d94ba 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queue_purge.erl @@ -11,30 +11,32 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queue_purge). --export([init/3, rest_init/2, resource_exists/2, is_authorized/2, allowed_methods/2, +-export([init/1, resource_exists/2, is_authorized/2, allowed_methods/2, delete_resource/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. allowed_methods(ReqData, Context) -> - {[<<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['DELETE', 'OPTIONS'], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_wm_queue:queue(ReqData) of diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl similarity index 51% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl index 1e6a3dc..2a67890 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_queues.erl @@ -11,36 +11,36 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_queues). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, - resource_exists/2, basic/1]). --export([variances/2, - augmented/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, + resource_exists/2, basic/1, augmented/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). --define(BASIC_COLUMNS, ["vhost", "name", "durable", "auto_delete", "exclusive", - "owner_pid", "arguments", "pid", "state"]). - --define(DEFAULT_SORT, ["vhost", "name"]). - %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. resource_exists(ReqData, Context) -> {case queues0(ReqData) of @@ -48,43 +48,31 @@ resource_exists(ReqData, Context) -> _ -> true end, ReqData, Context}. + to_json(ReqData, Context) -> try - Basic = basic_vhost_filtered(ReqData, Context), - Data = rabbit_mgmt_util:augment_resources(Basic, ?DEFAULT_SORT, - ?BASIC_COLUMNS, ReqData, - Context, fun augment/2), - rabbit_mgmt_util:reply(Data, ReqData, Context) + rabbit_mgmt_util:reply_list_or_paginate( + augmented(ReqData, Context), ReqData, Context) catch {error, invalid_range_parameters, Reason} -> - rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, - Context) + rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) end. is_authorized(ReqData, Context) -> rabbit_mgmt_util:is_authorized_vhost(ReqData, Context). %%-------------------------------------------------------------------- -%% Exported functions + +augmented(ReqData, Context) -> + rabbit_mgmt_db:augment_queues( + rabbit_mgmt_util:filter_vhost(basic(ReqData), ReqData, Context), + rabbit_mgmt_util:range_ceil(ReqData), basic). basic(ReqData) -> [rabbit_mgmt_format:queue(Q) || Q <- queues0(ReqData)] ++ [rabbit_mgmt_format:queue(Q#amqqueue{state = down}) || Q <- down_queues(ReqData)]. -augmented(ReqData, Context) -> - augment(rabbit_mgmt_util:filter_vhost(basic(ReqData), ReqData, Context), ReqData). - -%%-------------------------------------------------------------------- -%% Private helpers - -augment(Basic, ReqData) -> - rabbit_mgmt_db:augment_queues(Basic, rabbit_mgmt_util:range_ceil(ReqData), - basic). - -basic_vhost_filtered(ReqData, Context) -> - rabbit_mgmt_util:filter_vhost(basic(ReqData), ReqData, Context). - queues0(ReqData) -> rabbit_mgmt_util:all_or_one_vhost(ReqData, fun rabbit_amqqueue:list/1). diff --git a/deps/rabbitmq_management/src/rabbit_mgmt_wm_user.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_user.erl new file mode 100644 index 0000000..b62f17a --- /dev/null +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_user.erl @@ -0,0 +1,147 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License at +%% http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +%% License for the specific language governing rights and limitations +%% under the License. +%% +%% The Original Code is RabbitMQ Management Plugin. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_mgmt_wm_user). + +-export([init/1, resource_exists/2, to_json/2, + content_types_provided/2, content_types_accepted/2, + is_authorized/2, allowed_methods/2, accept_content/2, + delete_resource/2, user/1, put_user/1, put_user/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). + +-import(rabbit_misc, [pget/2]). + +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). +-include_lib("rabbit_common/include/rabbit.hrl"). + +%%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. + +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. + +content_types_provided(ReqData, Context) -> + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. + +content_types_accepted(ReqData, Context) -> + {[{"application/json", accept_content}], ReqData, Context}. + +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. + +resource_exists(ReqData, Context) -> + {case user(ReqData) of + {ok, _} -> true; + {error, _} -> false + end, ReqData, Context}. + +to_json(ReqData, Context) -> + {ok, User} = user(ReqData), + rabbit_mgmt_util:reply(rabbit_mgmt_format:internal_user(User), + ReqData, Context). + +accept_content(ReqData, Context) -> + Username = rabbit_mgmt_util:id(user, ReqData), + rabbit_mgmt_util:with_decode( + [], ReqData, Context, + fun(_, User) -> + put_user([{name, Username} | User]), + {true, ReqData, Context} + end). + +delete_resource(ReqData, Context) -> + User = rabbit_mgmt_util:id(user, ReqData), + rabbit_auth_backend_internal:delete_user(User), + {true, ReqData, Context}. + +is_authorized(ReqData, Context) -> + rabbit_mgmt_util:is_authorized_admin(ReqData, Context). + +%%-------------------------------------------------------------------- + +user(ReqData) -> + rabbit_auth_backend_internal:lookup_user(rabbit_mgmt_util:id(user, ReqData)). + +put_user(User) -> put_user(User, undefined). + +put_user(User, Version) -> + PasswordUpdateFun = + fun(Username) -> + case {proplists:is_defined(password, User), + proplists:is_defined(password_hash, User)} of + {true, _} -> + rabbit_auth_backend_internal:change_password( + Username, pget(password, User)); + {_, true} -> + HashingAlgorithm = hashing_algorithm(User, Version), + + Hash = rabbit_mgmt_util:b64decode_or_throw( + pget(password_hash, User)), + rabbit_auth_backend_internal:change_password_hash( + Username, Hash, HashingAlgorithm); + _ -> + rabbit_auth_backend_internal:clear_password(Username) + end + end, + put_user0(User, PasswordUpdateFun). + +put_user0(User, PasswordUpdateFun) -> + Username = pget(name, User), + Tags = case {pget(tags, User), pget(administrator, User)} of + {undefined, undefined} -> + throw({error, tags_not_present}); + {undefined, AdminS} -> + case rabbit_mgmt_util:parse_bool(AdminS) of + true -> [administrator]; + false -> [] + end; + {TagsS, _} -> + [list_to_atom(string:strip(T)) || + T <- string:tokens(binary_to_list(TagsS), ",")] + end, + case rabbit_auth_backend_internal:lookup_user(Username) of + {error, not_found} -> + rabbit_auth_backend_internal:add_user( + Username, rabbit_guid:binary(rabbit_guid:gen_secure(), "tmp")); + _ -> + ok + end, + PasswordUpdateFun(Username), + ok = rabbit_auth_backend_internal:set_tags(Username, Tags). + +hashing_algorithm(User, Version) -> + case pget(hashing_algorithm, User) of + undefined -> + case Version of + %% 3.6.1 and later versions are supposed to have + %% the algorithm exported and thus not need a default + <<"3.6.0">> -> rabbit_password_hashing_sha256; + <<"3.5.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.4.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.3.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.2.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.1.", _/binary>> -> rabbit_password_hashing_md5; + <<"3.0.", _/binary>> -> rabbit_password_hashing_md5; + _ -> rabbit_password:hashing_mod() + end; + Alg -> binary_to_atom(Alg, utf8) + end. diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl similarity index 65% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl index e6e0336..c6ba4f5 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_users.erl @@ -11,32 +11,38 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_users). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([variances/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([users/0]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context) -> rabbit_mgmt_util:reply_list(users(), ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl similarity index 74% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl index 034733d..09c8c52 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhost.erl @@ -11,40 +11,42 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_vhost). --export([init/3, rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2, id/1, put_vhost/2]). --export([variances/2]). +-export([finish_request/2]). +-export([encodings_provided/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{'*', accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>, <<"OPTIONS">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS'], ReqData, Context}. resource_exists(ReqData, Context) -> {rabbit_vhost:exists(id(ReqData)), ReqData, Context}. @@ -60,11 +62,11 @@ to_json(ReqData, Context) -> rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) end. -accept_content(ReqData0, Context) -> - Name = id(ReqData0), +accept_content(ReqData, Context) -> + Name = id(ReqData), rabbit_mgmt_util:with_decode( - [], ReqData0, Context, - fun(_, VHost, ReqData) -> + [], ReqData, Context, + fun(_, VHost) -> put_vhost(Name, rabbit_mgmt_util:parse_bool( pget(tracing, VHost))), {true, ReqData, Context} diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl similarity index 55% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl index 40e361e..faeb0f5 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_vhosts.erl @@ -11,43 +11,41 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_vhosts). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([variances/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). -export([basic/0, augmented/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). --define(BASIC_COLUMNS, ["name", "tracing", "pid"]). - --define(DEFAULT_SORT, ["name"]). - %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +init(_Config) -> {ok, #context{}}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. -to_json(ReqData, Context = #context{user = User}) -> +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. + +to_json(ReqData, Context) -> try - Basic = [rabbit_vhost:info(V) - || V <- rabbit_mgmt_util:list_visible_vhosts(User)], - Data = rabbit_mgmt_util:augment_resources(Basic, ?DEFAULT_SORT, - ?BASIC_COLUMNS, ReqData, - Context, fun augment/2), - rabbit_mgmt_util:reply(Data, ReqData, Context) + rabbit_mgmt_util:reply_list_or_paginate( + augmented(ReqData, Context),ReqData, Context) catch {error, invalid_range_parameters, Reason} -> rabbit_mgmt_util:bad_request(iolist_to_binary(Reason), ReqData, Context) @@ -58,9 +56,6 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- -augment(Basic, ReqData) -> - rabbit_mgmt_db:augment_vhosts(Basic, rabbit_mgmt_util:range(ReqData)). - augmented(ReqData, #context{user = User}) -> rabbit_mgmt_db:augment_vhosts( [rabbit_vhost:info(V) || V <- rabbit_mgmt_util:list_visible_vhosts(User)], diff --git a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl b/deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl similarity index 59% rename from rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl rename to deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl index 68ec3ed..5d262a7 100644 --- a/rabbitmq-server/deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl +++ b/deps/rabbitmq_management/src/rabbit_mgmt_wm_whoami.erl @@ -11,29 +11,34 @@ %% The Original Code is RabbitMQ Management Plugin. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_wm_whoami). --export([init/3, rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). --export([variances/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). +-export([finish_request/2, allowed_methods/2]). +-export([encodings_provided/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include("rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("rabbit_common/include/rabbit.hrl"). %%-------------------------------------------------------------------- +init(_Config) -> {ok, #context{}}. -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. +finish_request(ReqData, Context) -> + {ok, rabbit_mgmt_cors:set_headers(ReqData, Context), Context}. -rest_init(Req, _Config) -> - {ok, rabbit_mgmt_cors:set_headers(Req, ?MODULE), #context{}}. - -variances(Req, Context) -> - {[<<"accept-encoding">>, <<"origin">>], Req, Context}. +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'OPTIONS'], ReqData, Context}. content_types_provided(ReqData, Context) -> - {rabbit_mgmt_util:responder_map(to_json), ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. + +encodings_provided(ReqData, Context) -> + {[{"identity", fun(X) -> X end}, + {"gzip", fun(X) -> zlib:gzip(X) end}], ReqData, Context}. to_json(ReqData, Context = #context{user = User}) -> rabbit_mgmt_util:reply(rabbit_mgmt_format:user(User), ReqData, Context). diff --git a/deps/rabbitmq_management/src/rabbitmq_management.app.src b/deps/rabbitmq_management/src/rabbitmq_management.app.src new file mode 100644 index 0000000..6319f0f --- /dev/null +++ b/deps/rabbitmq_management/src/rabbitmq_management.app.src @@ -0,0 +1,22 @@ +{application, rabbitmq_management, + [{description, "RabbitMQ Management Console"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_mgmt_app, []}}, + {env, [{listener, [{port, 15672}]}, + {http_log_dir, none}, + {load_definitions, none}, + {rates_mode, basic}, + {sample_retention_policies, + %% List of {MaxAgeInSeconds, SampleEveryNSeconds} + [{global, [{605, 5}, {3660, 60}, {29400, 600}, {86400, 1800}]}, + {basic, [{605, 5}, {3600, 60}]}, + {detailed, [{10, 5}]}]}, + {process_stats_gc_timeout, 300000}, + {stats_event_max_backlog, 250}, + {cors_allow_origins, []}, + {cors_max_age, 1800} + ]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, xmerl, rabbitmq_web_dispatch, + amqp_client, rabbitmq_management_agent]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/CODE_OF_CONDUCT.md b/deps/rabbitmq_management_agent/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_agent/CODE_OF_CONDUCT.md rename to deps/rabbitmq_management_agent/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/CONTRIBUTING.md b/deps/rabbitmq_management_agent/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/CONTRIBUTING.md rename to deps/rabbitmq_management_agent/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/LICENSE b/deps/rabbitmq_management_agent/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_agent/LICENSE rename to deps/rabbitmq_management_agent/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_management_agent/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_agent/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_management_agent/LICENSE-MPL-RabbitMQ diff --git a/deps/rabbitmq_management_agent/Makefile b/deps/rabbitmq_management_agent/Makefile new file mode 100644 index 0000000..79f4f1c --- /dev/null +++ b/deps/rabbitmq_management_agent/Makefile @@ -0,0 +1,14 @@ +PROJECT = rabbitmq_management_agent + +DEPS = rabbit_common rabbit + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/deps/rabbitmq_management_agent/erlang.mk b/deps/rabbitmq_management_agent/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_management_agent/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/deps/rabbitmq_management_agent/rabbitmq-components.mk b/deps/rabbitmq_management_agent/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_management_agent/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl b/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl similarity index 87% rename from rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl rename to deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl index 8822522..11c181a 100644 --- a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl +++ b/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_agent_app). @@ -20,7 +20,7 @@ -export([start/2, stop/1]). start(_Type, _StartArgs) -> - rabbit_mgmt_agent_sup_sup:start_link(). + rabbit_mgmt_agent_sup:start_link(). stop(_State) -> ok. diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/include/rabbit_mgmt_records.hrl b/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup.erl similarity index 62% rename from rabbitmq-server/deps/rabbitmq_management_agent/include/rabbit_mgmt_records.hrl rename to deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup.erl index 9a19508..26adfe8 100644 --- a/rabbitmq-server/deps/rabbitmq_management_agent/include/rabbit_mgmt_records.hrl +++ b/deps/rabbitmq_management_agent/src/rabbit_mgmt_agent_sup.erl @@ -14,12 +14,18 @@ %% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% --record(context, {user, - password = none, - impl}). % storage for a context of the resource handler +-module(rabbit_mgmt_agent_sup). --record(range, {first :: integer(), - last :: integer(), - incr :: integer()}). +-behaviour(supervisor). +-export([init/1]). +-export([start_link/0]). +init([]) -> + ExternalStats = {rabbit_mgmt_external_stats, + {rabbit_mgmt_external_stats, start_link, []}, + permanent, 5000, worker, [rabbit_mgmt_external_stats]}, + {ok, {{one_for_one, 10, 10}, [ExternalStats]}}. + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl b/deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl rename to deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl index ef691c9..95545a3 100644 --- a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl +++ b/deps/rabbitmq_management_agent/src/rabbit_mgmt_db_handler.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_db_handler). @@ -44,14 +44,22 @@ add_handler() -> gc() -> erlang:garbage_collect(whereis(rabbit_event)). +%% some people have reasons to only run with the agent enabled: +%% make it possible for them to configure key management app +%% settings such as rates_mode. +get_management_env(Key) -> + rabbit_misc:get_env( + rabbitmq_management, Key, + rabbit_misc:get_env(rabbitmq_management_agent, Key, undefined)). + rates_mode() -> - case rabbit_mgmt_agent_config:get_env(rates_mode) of + case get_management_env(rates_mode) of undefined -> basic; Mode -> Mode end. handle_force_fine_statistics() -> - case rabbit_mgmt_agent_config:get_env(force_fine_statistics) of + case get_management_env(force_fine_statistics) of undefined -> ok; X -> @@ -87,14 +95,17 @@ init([]) -> handle_call(_Request, State) -> {ok, not_understood, State}. -handle_event(#event{type = Type} = Event, State) - when Type == connection_closed; Type == channel_closed; Type == queue_deleted; - Type == exchange_deleted; Type == vhost_deleted; - Type == consumer_deleted; Type == node_node_deleted; - Type == channel_consumer_deleted -> - gen_server:cast(rabbit_mgmt_metrics_gc:name(Type), {event, Event}), +handle_event(#event{type = Type} = Event, State) when Type == channel_stats; + Type == channel_created; + Type == channel_closed -> + gen_server:cast({global, rabbit_mgmt_channel_stats_collector}, {event, Event}), + {ok, State}; +handle_event(#event{type = Type} = Event, State) when Type == queue_stats; + Type == queue_deleted -> + gen_server:cast({global, rabbit_mgmt_queue_stats_collector}, {event, Event}), {ok, State}; -handle_event(_, State) -> +handle_event(Event, State) -> + gen_server:cast({global, rabbit_mgmt_event_collector}, {event, Event}), {ok, State}. handle_info(_Info, State) -> diff --git a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl b/deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl similarity index 79% rename from rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl rename to deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl index b71f3df..294cf67 100644 --- a/rabbitmq-server/deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl +++ b/deps/rabbitmq_management_agent/src/rabbit_mgmt_external_stats.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Management Console. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mgmt_external_stats). @@ -28,16 +28,16 @@ -include_lib("rabbit_common/include/rabbit.hrl"). --define(METRICS_KEYS, [fd_used, sockets_used, mem_used, disk_free, proc_used, gc_num, - gc_bytes_reclaimed, context_switches]). - --define(PERSISTER_KEYS, [persister_stats]). - --define(OTHER_KEYS, [name, partitions, os_pid, fd_total, sockets_total, mem_limit, - mem_alarm, disk_free_limit, disk_free_alarm, proc_total, - rates_mode, uptime, run_queue, processors, exchange_types, - auth_mechanisms, applications, contexts, log_file, - sasl_log_file, db_dir, config_files, net_ticktime, enabled_plugins]). +-define(REFRESH_RATIO, 5000). +-define(KEYS, [name, partitions, os_pid, fd_used, fd_total, + sockets_used, sockets_total, mem_used, mem_limit, mem_alarm, + disk_free_limit, disk_free, disk_free_alarm, + proc_used, proc_total, rates_mode, + uptime, run_queue, processors, exchange_types, + auth_mechanisms, applications, contexts, + log_file, sasl_log_file, db_dir, config_files, net_ticktime, + enabled_plugins, persister_stats, gc_num, gc_bytes_reclaimed, + context_switches]). %%-------------------------------------------------------------------- @@ -45,8 +45,7 @@ fd_total, fhc_stats, node_owners, - last_ts, - interval + last_ts }). %%-------------------------------------------------------------------- @@ -57,13 +56,7 @@ start_link() -> %%-------------------------------------------------------------------- get_used_fd() -> - case get_used_fd(os:type()) of - Fd when is_number(Fd) -> - Fd; - _Other -> - %% Defaults to 0 if data is not available - 0 - end. + get_used_fd(os:type()). get_used_fd({unix, linux}) -> case file:list_dir("/proc/" ++ os:getpid() ++ "/fd") of @@ -82,8 +75,14 @@ get_used_fd({unix, BSD}) lists:all(Digit, (lists:nth(4, string:tokens(Line, " ")))) end, string:tokens(Output, "\n"))) catch _:Error -> - log_fd_error("Could not parse fstat output:~n~s~n~p~n", - [Output, {Error, erlang:get_stacktrace()}]) + case get(logged_used_fd_error) of + undefined -> rabbit_log:warning( + "Could not parse fstat output:~n~s~n~p~n", + [Output, {Error, erlang:get_stacktrace()}]), + put(logged_used_fd_error, true); + _ -> ok + end, + unknown end; get_used_fd({unix, _}) -> @@ -91,7 +90,7 @@ get_used_fd({unix, _}) -> "lsof -d \"0-9999999\" -lna -p ~s || echo failed", [os:getpid()]), Res = os:cmd(Cmd), case string:right(Res, 7) of - "failed\n" -> log_fd_error("Could not obtain lsof output~n", []); + "failed\n" -> unknown; _ -> string:words(Res, $\n) - 1 end; @@ -132,16 +131,12 @@ get_used_fd({win32, _}) -> Handle = rabbit_misc:os_cmd( "handle.exe /accepteula -s -p " ++ os:getpid() ++ " 2> nul"), case Handle of - [] -> log_fd_error("Could not find handle.exe, please install from " - "sysinternals~n", []); - _ -> case find_files_line(string:tokens(Handle, "\r\n")) of - unknown -> - log_fd_error("Could not parse handle.exe output: ~p~n", - [Handle]); - Any -> - Any - end - end. + [] -> install_handle_from_sysinternals; + _ -> find_files_line(string:tokens(Handle, "\r\n")) + end; + +get_used_fd(_) -> + unknown. find_files_line([]) -> unknown; @@ -163,12 +158,6 @@ get_disk_free_limit() -> ?SAFE_CALL(rabbit_disk_monitor:get_disk_free_limit(), get_disk_free() -> ?SAFE_CALL(rabbit_disk_monitor:get_disk_free(), disk_free_monitoring_disabled). -log_fd_error(Fmt, Args) -> - case get(logged_used_fd_error) of - undefined -> rabbit_log:warning(Fmt, Args), - put(logged_used_fd_error, true); - _ -> ok - end. %%-------------------------------------------------------------------- infos(Items, State) -> [{Item, i(Item, State)} || Item <- Items]. @@ -182,8 +171,7 @@ i(sockets_used, _State) -> i(sockets_total, _State) -> proplists:get_value(sockets_limit, file_handle_cache:info([sockets_limit])); i(os_pid, _State) -> list_to_binary(os:getpid()); - -i(mem_used, _State) -> vm_memory_monitor:get_process_memory(); +i(mem_used, _State) -> erlang:memory(total); i(mem_limit, _State) -> vm_memory_monitor:get_memory_limit(); i(mem_alarm, _State) -> resource_alarm_set(memory); i(proc_used, _State) -> erlang:system_info(process_count); @@ -337,14 +325,17 @@ format_mochiweb_option(_K, V) -> %%-------------------------------------------------------------------- init([]) -> - {ok, Interval} = application:get_env(rabbit, collect_statistics_interval), State = #state{fd_total = file_handle_cache:ulimit(), fhc_stats = file_handle_cache_stats:get(), - node_owners = sets:new(), - interval = Interval}, - %% We can update stats straight away as they need to be available - %% when the mgmt plugin starts a collector - {ok, emit_update(State)}. + node_owners = sets:new()}, + %% If we emit an update straight away we will do so just before + %% the mgmt db starts up - and then have to wait ?REFRESH_RATIO + %% until we send another. So let's have a shorter wait in the hope + %% that the db will have started by the time we emit an update, + %% and thus shorten that little gap at startup where mgmt knows + %% nothing about any nodes. + erlang:send_after(1000, self(), emit_update), + {ok, State}. handle_call(_Req, _From, State) -> {reply, unknown_request, State}. @@ -366,14 +357,9 @@ code_change(_, State, _) -> {ok, State}. emit_update(State0) -> State = update_state(State0), - MStats = infos(?METRICS_KEYS, State), - [{persister_stats, PStats0}] = PStats = infos(?PERSISTER_KEYS, State), - [{name, _Name} | OStats0] = OStats = infos(?OTHER_KEYS, State), - rabbit_core_metrics:node_stats(persister_metrics, PStats0), - rabbit_core_metrics:node_stats(coarse_metrics, MStats), - rabbit_core_metrics:node_stats(node_metrics, OStats0), - rabbit_event:notify(node_stats, PStats ++ MStats ++ OStats), - erlang:send_after(State#state.interval, self(), emit_update), + Stats = infos(?KEYS, State), + rabbit_event:notify(node_stats, Stats), + erlang:send_after(?REFRESH_RATIO, self(), emit_update), emit_node_node_stats(State). emit_node_node_stats(State = #state{node_owners = Owners}) -> @@ -382,13 +368,11 @@ emit_node_node_stats(State = #state{node_owners = Owners}) -> Dead = sets:to_list(sets:subtract(Owners, NewOwners)), [rabbit_event:notify( node_node_deleted, [{route, Route}]) || {Node, _Owner} <- Dead, - Route <- [{node(), Node}, - {Node, node()}]], - [begin - rabbit_core_metrics:node_node_stats({node(), Node}, Stats), - rabbit_event:notify( - node_node_stats, [{route, {node(), Node}} | Stats]) - end || {Node, _Owner, Stats} <- Links], + Route <- [{node(), Node}, + {Node, node()}]], + [rabbit_event:notify( + node_node_stats, [{route, {node(), Node}} | Stats]) || + {Node, _Owner, Stats} <- Links], State#state{node_owners = NewOwners}. update_state(State0) -> diff --git a/deps/rabbitmq_management_agent/src/rabbitmq_management_agent.app.src b/deps/rabbitmq_management_agent/src/rabbitmq_management_agent.app.src new file mode 100644 index 0000000..7990157 --- /dev/null +++ b/deps/rabbitmq_management_agent/src/rabbitmq_management_agent.app.src @@ -0,0 +1,8 @@ +{application, rabbitmq_management_agent, + [{description, "RabbitMQ Management Agent"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_mgmt_agent_app, []}}, + {env, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/CODE_OF_CONDUCT.md b/deps/rabbitmq_management_visualiser/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/CODE_OF_CONDUCT.md rename to deps/rabbitmq_management_visualiser/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/CONTRIBUTING.md b/deps/rabbitmq_management_visualiser/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/CONTRIBUTING.md rename to deps/rabbitmq_management_visualiser/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE b/deps/rabbitmq_management_visualiser/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE rename to deps/rabbitmq_management_visualiser/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE-BSD-glMatrix b/deps/rabbitmq_management_visualiser/LICENSE-BSD-glMatrix similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE-BSD-glMatrix rename to deps/rabbitmq_management_visualiser/LICENSE-BSD-glMatrix diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_management_visualiser/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_management_visualiser/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/Makefile b/deps/rabbitmq_management_visualiser/Makefile similarity index 64% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/Makefile rename to deps/rabbitmq_management_visualiser/Makefile index 25d1305..600e846 100644 --- a/rabbitmq-server/deps/rabbitmq_management_visualiser/Makefile +++ b/deps/rabbitmq_management_visualiser/Makefile @@ -1,10 +1,7 @@ PROJECT = rabbitmq_management_visualiser -PROJECT_DESCRIPTION = RabbitMQ Visualiser -DEPS = rabbit_common rabbit rabbitmq_management -TEST_DEPS = rabbitmq_ct_helpers +DEPS = rabbit_common rabbit rabbitmq_management webmachine -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/README.md b/deps/rabbitmq_management_visualiser/README similarity index 71% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/README.md rename to deps/rabbitmq_management_visualiser/README index 7d1cd94..18ff2ac 100644 --- a/rabbitmq-server/deps/rabbitmq_management_visualiser/README.md +++ b/deps/rabbitmq_management_visualiser/README @@ -1,14 +1,9 @@ -# RabbitMQ Visualiser +RabbitMQ Visualiser +=================== -This experimental plugin that visualizes RabbitMQ topology and message flow. -It is **DEPRECATED** and will not ship with RabbitMQ as of 3.7.0. - -## Project Maturity - -This project was an experiment because it is no longer under development. - -## Usage +Usage +----- This is a plugin for the RabbitMQ Management Plugin that provides an HTML Canvas for rendering configured broker topology. The current main @@ -41,3 +36,21 @@ and clicking on the relevant 'Show' button. The 'Display' check-boxes turn off and on entire resource classes, and resets positioning. + + +Compatibility and Performance Notes +----------------------------------- + +Does work in recent versions of Safari both on OS X and Windows. + +Does work in Firefox (at least version 4.0). + +Does work in Chrome. + +Does not work in Internet Explorer. No error is given, but it doesn't +work. + +Best performance is with Chrome. Note though that in some cases it has +been seen that hardware rendering (use of GPU) can actually slow down +performance. Some experimentation with browser flags and settings may +be necessary to ensure smooth operation. diff --git a/deps/rabbitmq_management_visualiser/erlang.mk b/deps/rabbitmq_management_visualiser/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_management_visualiser/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/license_info b/deps/rabbitmq_management_visualiser/license_info similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/license_info rename to deps/rabbitmq_management_visualiser/license_info diff --git a/deps/rabbitmq_management_visualiser/priv/www/js/visualiser.js b/deps/rabbitmq_management_visualiser/priv/www/js/visualiser.js new file mode 100644 index 0000000..8b4f9a2 --- /dev/null +++ b/deps/rabbitmq_management_visualiser/priv/www/js/visualiser.js @@ -0,0 +1,3 @@ +dispatcher_add(function(sammy) {}); + +NAVIGATION['Visualiser'] = ['visualiser/', "management"]; diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/index.html b/deps/rabbitmq_management_visualiser/priv/www/visualiser/index.html similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/index.html rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/index.html diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix-min.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix-min.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix-min.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix-min.js diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/glMatrix.js diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/main.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/main.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/main.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/main.js diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/model.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/model.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/model.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/model.js diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/octtree.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/octtree.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/octtree.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/octtree.js diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/physics.js b/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/physics.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/priv/www/visualiser/js/physics.js rename to deps/rabbitmq_management_visualiser/priv/www/visualiser/js/physics.js diff --git a/deps/rabbitmq_management_visualiser/rabbitmq-components.mk b/deps/rabbitmq_management_visualiser/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_management_visualiser/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl b/deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl similarity index 57% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl rename to deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl index 8119667..d76da5b 100644 --- a/rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl +++ b/deps/rabbitmq_management_visualiser/src/rabbit_mgmt_wm_all.erl @@ -11,25 +11,23 @@ %% The Original Code is RabbitMQ Visualiser. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -module(rabbit_mgmt_wm_all). --export([init/3]). --export([rest_init/2, to_json/2, content_types_provided/2, is_authorized/2, +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2, resource_exists/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_util:vhost(ReqData) of @@ -39,16 +37,14 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> rabbit_mgmt_util:reply( - rabbit_mgmt_format:strip_pids( - [{Key, Mod:augmented(ReqData, Context)} - || {Key, Mod} <- [{queues, rabbit_mgmt_wm_queues}, - {exchanges, rabbit_mgmt_wm_exchanges}, - {bindings, rabbit_mgmt_wm_bindings}, - {channels, rabbit_mgmt_wm_channels}, - {connections, rabbit_mgmt_wm_connections}, - {vhosts, rabbit_mgmt_wm_vhosts}] - ]), - ReqData, Context). + [{Key, Mod:augmented(ReqData, Context)} + || {Key, Mod} <- [{queues, rabbit_mgmt_wm_queues}, + {exchanges, rabbit_mgmt_wm_exchanges}, + {bindings, rabbit_mgmt_wm_bindings}, + {channels, rabbit_mgmt_wm_channels}, + {connections, rabbit_mgmt_wm_connections}, + {vhosts, rabbit_mgmt_wm_vhosts}] + ], ReqData, Context). is_authorized(ReqData, Context) -> rabbit_mgmt_util:is_authorized(ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl b/deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl similarity index 81% rename from rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl rename to deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl index da12c12..27992dd 100644 --- a/rabbitmq-server/deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl +++ b/deps/rabbitmq_management_visualiser/src/rabbit_visualiser_mgmt.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Visualiser. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_visualiser_mgmt). @@ -20,6 +20,6 @@ -export([dispatcher/0, web_ui/0]). -dispatcher() -> [{"/all", rabbit_mgmt_wm_all, []}, - {"/all/:vhost", rabbit_mgmt_wm_all, []}]. +dispatcher() -> [{["all"], rabbit_mgmt_wm_all, []}, + {["all", vhost], rabbit_mgmt_wm_all, []}]. web_ui() -> [{javascript, <<"visualiser.js">>}]. diff --git a/deps/rabbitmq_management_visualiser/src/rabbitmq_management_visualiser.app.src b/deps/rabbitmq_management_visualiser/src/rabbitmq_management_visualiser.app.src new file mode 100644 index 0000000..28f70fe --- /dev/null +++ b/deps/rabbitmq_management_visualiser/src/rabbitmq_management_visualiser.app.src @@ -0,0 +1,6 @@ +{application, rabbitmq_management_visualiser, + [{description, "RabbitMQ Visualiser"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit, rabbitmq_management]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/CODE_OF_CONDUCT.md b/deps/rabbitmq_mqtt/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/CODE_OF_CONDUCT.md rename to deps/rabbitmq_mqtt/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/CONTRIBUTING.md b/deps/rabbitmq_mqtt/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/CONTRIBUTING.md rename to deps/rabbitmq_mqtt/CONTRIBUTING.md diff --git a/deps/rabbitmq_mqtt/Makefile b/deps/rabbitmq_mqtt/Makefile new file mode 100644 index 0000000..218bd34 --- /dev/null +++ b/deps/rabbitmq_mqtt/Makefile @@ -0,0 +1,22 @@ +PROJECT = rabbitmq_mqtt + +DEPS = ranch rabbit_common rabbit amqp_client +TEST_DEPS = emqttc ct_helper rabbitmq_ct_helpers + +dep_ct_helper = git https://github.com/extend/ct_helper.git master +dep_emqttc = git https://github.com/emqtt/emqttc.git master + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk + + +clean:: + if test -d test/java_SUITE_data; then cd test/java_SUITE_data && make clean; fi diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/README.md b/deps/rabbitmq_mqtt/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/README.md rename to deps/rabbitmq_mqtt/README.md diff --git a/deps/rabbitmq_mqtt/erlang.mk b/deps/rabbitmq_mqtt/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_mqtt/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl b/deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl similarity index 80% rename from rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl rename to deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl index f46f00d..dbc9928 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl +++ b/deps/rabbitmq_mqtt/include/rabbit_mqtt.hrl @@ -61,36 +61,3 @@ %% the table name -record(retained_message, {topic, mqtt_msg}). - --define(INFO_ITEMS, - [host, - port, - peer_host, - peer_port, - protocol, - channels, - channel_max, - frame_max, - client_properties, - ssl, - ssl_protocol, - ssl_key_exchange, - ssl_cipher, - ssl_hash, - conn_name, - connection_state, - connection, - consumer_tags, - unacked_pubs, - awaiting_ack, - awaiting_seqno, - message_id, - client_id, - clean_sess, - will_msg, - exchange, - ssl_login_name, - retainer_pid, - user, - vhost]). - diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt_frame.hrl b/deps/rabbitmq_mqtt/include/rabbit_mqtt_frame.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt_frame.hrl rename to deps/rabbitmq_mqtt/include/rabbit_mqtt_frame.hrl diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt_retained_msg_store.hrl b/deps/rabbitmq_mqtt/include/rabbit_mqtt_retained_msg_store.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/include/rabbit_mqtt_retained_msg_store.hrl rename to deps/rabbitmq_mqtt/include/rabbit_mqtt_retained_msg_store.hrl diff --git a/deps/rabbitmq_mqtt/rabbitmq-components.mk b/deps/rabbitmq_mqtt/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_mqtt/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt.erl index 7f69765..d69d916 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl similarity index 86% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl index 1f90704..50361ef 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_collector.erl @@ -11,14 +11,14 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_collector). -behaviour(gen_server). --export([start_link/0, register/2, unregister/2, list/0]). +-export([start_link/0, register/2, unregister/2]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). @@ -38,9 +38,6 @@ register(ClientId, Pid) -> unregister(ClientId, Pid) -> gen_server:call(rabbit_mqtt_collector, {unregister, ClientId, Pid}, infinity). -list() -> - gen_server:call(rabbit_mqtt_collector, list). - %%---------------------------------------------------------------------------- init([]) -> @@ -69,9 +66,6 @@ handle_call({unregister, ClientId, Pid}, _From, State = #state{client_ids = Ids} end, {reply, Reply, State#state{ client_ids = Ids1 }}; -handle_call(list, _From, State = #state{client_ids = Ids}) -> - {reply, dict:to_list(Ids), State}; - handle_call(Msg, _From, State) -> {stop, {unhandled_call, Msg}, State}. @@ -85,9 +79,8 @@ handle_info({'DOWN', MRef, process, DownPid, _Reason}, State = #state{client_ids = Ids}) -> Ids1 = dict:filter(fun (ClientId, {Pid, M}) when Pid =:= DownPid, MRef =:= M -> - rabbit_log:log(connection, warning, - "MQTT disconnect from ~p~n", - [ClientId]), + rabbit_log:warning("MQTT disconnect from ~p~n", + [ClientId]), false; (_, _) -> true diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl index f9e7203..a0ffec2 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_connection_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_connection_sup). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl index 225af20..0b80925 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_frame.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_frame). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl similarity index 81% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl index 9c2d6a5..f204794 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_processor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_processor). @@ -21,7 +21,7 @@ close_connection/1]). %% for testing purposes --export([get_vhost_username/1, get_vhost/3, get_vhost_from_user_mapping/2]). +-export([get_vhost_username/1]). -include_lib("amqp_client/include/amqp_client.hrl"). -include("rabbit_mqtt_frame.hrl"). @@ -96,13 +96,13 @@ process_request(?CONNECT, _ -> case creds(Username, Password, SSLLoginName) of nocreds -> - log(error, "MQTT login failed: no credentials provided~n"), + rabbit_log:error("MQTT login failed: no credentials provided~n"), {?CONNACK_CREDENTIALS, PState}; {invalid_creds, {undefined, Pass}} when is_list(Pass) -> - log(error, "MQTT login failed: no user username is provided"), + rabbit_log:error("MQTT login failed: no user username is provided"), {?CONNACK_CREDENTIALS, PState}; {invalid_creds, {User, undefined}} when is_list(User) -> - log(error, "MQTT login failed for ~p: no password provided", [User]), + rabbit_log:error("MQTT login failed for ~p: no password provided", [User]), {?CONNACK_CREDENTIALS, PState}; {UserBin, PassBin} -> case process_login(UserBin, PassBin, ProtoVersion, PState) of @@ -455,110 +455,39 @@ make_will_msg(#mqtt_frame_connect{ will_retain = Retain, process_login(UserBin, PassBin, ProtoVersion, #proc_state{ channels = {undefined, undefined}, socket = Sock, - adapter_info = AdapterInfo, - ssl_login_name = SslLoginName}) -> - {ok, {_, _, _, ToPort}} = rabbit_net:socket_ends(Sock, inbound), - {VHostPickedUsing, {VHost, UsernameBin}} = get_vhost(UserBin, SslLoginName, ToPort), - log(info, - "MQTT vhost picked using ~s~n", - [human_readable_vhost_lookup_strategy(VHostPickedUsing)]), - case rabbit_vhost:exists(VHost) of - true -> - case amqp_connection:start(#amqp_params_direct{ - username = UsernameBin, - password = PassBin, - virtual_host = VHost, - adapter_info = set_proto_version(AdapterInfo, ProtoVersion)}) of - {ok, Connection} -> - case rabbit_access_control:check_user_loopback(UsernameBin, Sock) of - ok -> - [{internal_user, InternalUser}] = amqp_connection:info( - Connection, [internal_user]), - {?CONNACK_ACCEPT, Connection, VHost, - #auth_state{user = InternalUser, - username = UsernameBin, - vhost = VHost}}; - not_allowed -> - amqp_connection:close(Connection), - log(warning, - "MQTT login failed for ~p access_refused " - "(access must be from localhost)~n", - [binary_to_list(UsernameBin)]), - ?CONNACK_AUTH - end; - {error, {auth_failure, Explanation}} -> - log(error, "MQTT login failed for ~p auth_failure: ~s~n", - [binary_to_list(UserBin), Explanation]), - ?CONNACK_CREDENTIALS; - {error, access_refused} -> - log(warning, "MQTT login failed for ~p access_refused " - "(vhost access not allowed)~n", - [binary_to_list(UserBin)]), - ?CONNACK_AUTH; - {error, not_allowed} -> - %% when vhost allowed for TLS connection - log(warning, "MQTT login failed for ~p access_refused " - "(vhost access not allowed)~n", - [binary_to_list(UserBin)]), + adapter_info = AdapterInfo }) -> + {VHost, UsernameBin} = get_vhost_username(UserBin), + case amqp_connection:start(#amqp_params_direct{ + username = UsernameBin, + password = PassBin, + virtual_host = VHost, + adapter_info = set_proto_version(AdapterInfo, ProtoVersion)}) of + {ok, Connection} -> + case rabbit_access_control:check_user_loopback(UsernameBin, Sock) of + ok -> + [{internal_user, InternalUser}] = amqp_connection:info( + Connection, [internal_user]), + {?CONNACK_ACCEPT, Connection, VHost, + #auth_state{user = InternalUser, + username = UsernameBin, + vhost = VHost}}; + not_allowed -> + amqp_connection:close(Connection), + rabbit_log:warning( + "MQTT login failed for ~p access_refused " + "(access must be from localhost)~n", + [binary_to_list(UsernameBin)]), ?CONNACK_AUTH end; - false -> - log(error, "MQTT login failed for ~p auth_failure: vhost ~s does not exist~n", - [binary_to_list(UserBin), VHost]), - ?CONNACK_CREDENTIALS - end. - -get_vhost(UserBin, none, Port) -> - get_vhost_no_ssl(UserBin, Port); -get_vhost(UserBin, undefined, Port) -> - get_vhost_no_ssl(UserBin, Port); -get_vhost(UserBin, SslLogin, Port) -> - get_vhost_ssl(UserBin, SslLogin, Port). - -get_vhost_no_ssl(UserBin, Port) -> - case vhost_in_username(UserBin) of - true -> - {vhost_in_username_or_default, get_vhost_username(UserBin)}; - false -> - PortVirtualHostMapping = rabbit_runtime_parameters:value_global( - mqtt_port_to_vhost_mapping - ), - case get_vhost_from_port_mapping(Port, PortVirtualHostMapping) of - undefined -> - {default_vhost, {rabbit_mqtt_util:env(vhost), UserBin}}; - VHost -> - {port_to_vhost_mapping, {VHost, UserBin}} - end - end. - -get_vhost_ssl(UserBin, SslLoginName, Port) -> - UserVirtualHostMapping = rabbit_runtime_parameters:value_global( - mqtt_default_vhosts - ), - case get_vhost_from_user_mapping(SslLoginName, UserVirtualHostMapping) of - undefined -> - PortVirtualHostMapping = rabbit_runtime_parameters:value_global( - mqtt_port_to_vhost_mapping - ), - case get_vhost_from_port_mapping(Port, PortVirtualHostMapping) of - undefined -> - {vhost_in_username_or_default, get_vhost_username(UserBin)}; - VHostFromPortMapping -> - {port_to_vhost_mapping, {VHostFromPortMapping, UserBin}} - end; - VHostFromCertMapping -> - {cert_to_vhost_mapping, {VHostFromCertMapping, UserBin}} - end. - -vhost_in_username(UserBin) -> - case application:get_env(?APP, ignore_colons_in_username) of - {ok, true} -> false; - _ -> - %% split at the last colon, disallowing colons in username - case re:split(UserBin, ":(?!.*?:)") of - [_, _] -> true; - [UserBin] -> false - end + {error, {auth_failure, Explanation}} -> + rabbit_log:error("MQTT login failed for ~p auth_failure: ~s~n", + [binary_to_list(UserBin), Explanation]), + ?CONNACK_CREDENTIALS; + {error, access_refused} -> + rabbit_log:warning("MQTT login failed for ~p access_refused " + "(vhost access not allowed)~n", + [binary_to_list(UserBin)]), + ?CONNACK_AUTH end. get_vhost_username(UserBin) -> @@ -573,38 +502,6 @@ get_vhost_username(UserBin) -> end end. -get_vhost_from_user_mapping(_User, not_found) -> - undefined; -get_vhost_from_user_mapping(User, Mapping) -> - case rabbit_misc:pget(User, Mapping) of - undefined -> - undefined; - VHost -> - VHost - end. - -get_vhost_from_port_mapping(_Port, not_found) -> - undefined; -get_vhost_from_port_mapping(Port, Mapping) -> - Res = case rabbit_misc:pget(rabbit_data_coercion:to_binary(Port), Mapping) of - undefined -> - undefined; - VHost -> - VHost - end, - Res. - -human_readable_vhost_lookup_strategy(vhost_in_username_or_default) -> - "vhost in username or default"; -human_readable_vhost_lookup_strategy(port_to_vhost_mapping) -> - "MQTT port to vhost mapping"; -human_readable_vhost_lookup_strategy(cert_to_vhost_mapping) -> - "client certificate to vhost mapping"; -human_readable_vhost_lookup_strategy(default_vhost) -> - "plugin configuration or default"; -human_readable_vhost_lookup_strategy(Val) -> - atom_to_list(Val). - creds(User, Pass, SSLLoginName) -> DefaultUser = rabbit_mqtt_util:env(default_user), DefaultPass = rabbit_mqtt_util:env(default_pass), @@ -697,27 +594,8 @@ ensure_queue(Qos, #proc_state{ channels = {Channel, _}, {Q, PState} end. -send_will(PState = #proc_state{will_msg = undefined}) -> - PState; - -send_will(PState = #proc_state{will_msg = WillMsg = #mqtt_msg{retain = Retain, - topic = Topic}, - retainer_pid = RPid, - channels = {ChQos0, ChQos1}}) -> - amqp_pub(WillMsg, PState), - case Retain of - false -> ok; - true -> hand_off_to_retainer(RPid, Topic, WillMsg) - end, - case ChQos1 of - undefined -> ok; - _ -> amqp_channel:close(ChQos1) - end, - case ChQos0 of - undefined -> ok; - _ -> amqp_channel:close(ChQos0) - end, - PState #proc_state{ channels = {undefined, undefined} }. +send_will(PState = #proc_state{ will_msg = WillMsg }) -> + amqp_pub(WillMsg, PState). amqp_pub(undefined, PState) -> PState; @@ -776,7 +654,7 @@ human_readable_mqtt_version(_) -> "N/A". send_client(Frame, #proc_state{ socket = Sock }) -> - %log(info, "MQTT sending frame ~p ~n", [Frame]), + %rabbit_log:info("MQTT sending frame ~p ~n", [Frame]), rabbit_net:port_command(Sock, rabbit_mqtt_frame:serialise(Frame)). close_connection(PState = #proc_state{ connection = undefined }) -> @@ -820,7 +698,3 @@ check_topic_access(TopicName, Access, kind = topic, name = TopicName}, rabbit_access_control:check_resource_access(User, Resource, Access). - -log(Level, Fmt) -> log(Level, Fmt, []). - -log(Level, Fmt, Args) -> rabbit_log:log(connection, Level, Fmt, Args). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl similarity index 81% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl index 4fd16b0..7df1a14 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_reader.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_reader). @@ -24,14 +24,10 @@ -export([conserve_resources/3, start_keepalive/2]). -export([ssl_login_name/1]). --export([info/2]). -include_lib("amqp_client/include/amqp_client.hrl"). -include("rabbit_mqtt.hrl"). --define(SIMPLE_METRICS, [pid, recv_oct, send_oct, reductions]). --define(OTHER_METRICS, [recv_cnt, send_cnt, send_pend, garbage_collection, state]). - %%---------------------------------------------------------------------------- start_link(KeepaliveSup, Ref, Sock) -> @@ -53,17 +49,11 @@ conserve_resources(Pid, _, {_, Conserve, _}) -> Pid ! {conserve_resources, Conserve}, ok. -info(Pid, InfoItems) -> - case InfoItems -- ?INFO_ITEMS of - [] -> gen_server2:call(Pid, {info, InfoItems}); - UnknownItems -> throw({bad_argument, UnknownItems}) - end. - %%---------------------------------------------------------------------------- init([KeepaliveSup, Ref, Sock]) -> process_flag(trap_exit, true), - rabbit_networking:accept_ack(Ref, Sock), + rabbit_net:accept_ack(Ref, Sock), case rabbit_net:connection_string(Sock, inbound) of {ok, ConnStr} -> log(debug, "MQTT accepting TCP connection ~p (~s)~n", [self(), ConnStr]), @@ -95,14 +85,6 @@ init([KeepaliveSup, Ref, Sock]) -> terminate({network_error, Reason}, undefined) end. -handle_call({info, InfoItems}, _From, State) -> - Infos = lists:map( - fun(InfoItem) -> - {InfoItem, info_internal(InfoItem, State)} - end, - InfoItems), - {reply, Infos, State}; - handle_call(Msg, From, State) -> {stop, {mqtt_unexpected_call, Msg, From}, State}. @@ -260,7 +242,7 @@ process_received_bytes(Bytes, State = #state{ parse_state = ParseState, proc_state = ProcState, conn_name = ConnStr }) -> - case parse(Bytes, ParseState) of + case rabbit_mqtt_frame:parse(Bytes, ParseState) of {more, ParseState1} -> {noreply, ensure_stats_timer(control_throttle( State #state{ parse_state = ParseState1 })), @@ -275,22 +257,18 @@ process_received_bytes(Bytes, proc_state = ProcState1, connection = ConnPid }); {error, Reason, ProcState1} -> - log(info, "MQTT protocol error ~p for connection ~s~n", + log(info, "MQTT protocol error ~p for connection ~p~n", [Reason, ConnStr]), {stop, {shutdown, Reason}, pstate(State, ProcState1)}; {error, Error} -> - log(error, "MQTT detected framing error '~p' for connection ~s~n", + log(error, "MQTT detected framing error '~p' for connection ~p~n", [Error, ConnStr]), {stop, {shutdown, Error}, State}; {stop, ProcState1} -> {stop, normal, pstate(State, ProcState1)} end; - {error, {cannot_parse, Error, Stacktrace}} -> - log(error, "MQTT cannot parse frame for connection '~s', unparseable payload: ~p, error: {~p, ~p} ~n", - [ConnStr, Bytes, Error, Stacktrace]), - {stop, {shutdown, Error}, State}; {error, Error} -> - log(error, "MQTT detected framing error '~p' for connection ~s~n", + log(error, "MQTT detected framing error '~p' for connection ~p~n", [ConnStr, Error]), {stop, {shutdown, Error}, State} end. @@ -307,13 +285,6 @@ pstate(State = #state {}, PState = #proc_state{}) -> State #state{ proc_state = PState }. %%---------------------------------------------------------------------------- -parse(Bytes, ParseState) -> - try - rabbit_mqtt_frame:parse(Bytes, ParseState) - catch - _:Reason -> - {error, {cannot_parse, Reason, erlang:get_stacktrace()}} - end. log(Level, Fmt, Args) -> rabbit_log:log(connection, Level, Fmt, Args). @@ -372,55 +343,20 @@ maybe_process_deferred_recv(State = #state{ deferred_recv = Data, socket = Sock handle_info({inet_async, Sock, noref, {ok, Data}}, State#state{ deferred_recv = undefined }). -maybe_emit_stats(undefined) -> - ok; maybe_emit_stats(State) -> rabbit_event:if_enabled(State, #state.stats_timer, fun() -> emit_stats(State) end). -emit_stats(State=#state{connection = C}) when C == none; C == undefined -> - %% Avoid emitting stats on terminate when the connection has not yet been - %% established, as this causes orphan entries on the stats database - State1 = rabbit_event:reset_stats_timer(State, #state.stats_timer), - ensure_stats_timer(State1); -emit_stats(State) -> - [{_, Pid}, {_, Recv_oct}, {_, Send_oct}, {_, Reductions}] = I - = infos(?SIMPLE_METRICS, State), - Infos = infos(?OTHER_METRICS, State), - rabbit_core_metrics:connection_stats(Pid, Infos), - rabbit_core_metrics:connection_stats(Pid, Recv_oct, Send_oct, Reductions), - rabbit_event:notify(connection_stats, Infos ++ I), +emit_stats(State=#state{socket=Sock, connection_state=ConnState, connection=Conn}) -> + SockInfos = case rabbit_net:getstat(Sock, + [recv_oct, recv_cnt, send_oct, send_cnt, send_pend]) of + {ok, SI} -> SI; + {error, _} -> [] + end, + Infos = [{pid, Conn}, {state, ConnState}|SockInfos], + rabbit_event:notify(connection_stats, Infos), State1 = rabbit_event:reset_stats_timer(State, #state.stats_timer), ensure_stats_timer(State1). ensure_stats_timer(State = #state{}) -> rabbit_event:ensure_stats_timer(State, #state.stats_timer, emit_stats). - -infos(Items, State) -> [{Item, info_internal(Item, State)} || Item <- Items]. - -info_internal(pid, State) -> info_internal(connection, State); -info_internal(SockStat, #state{socket = Sock}) when SockStat =:= recv_oct; - SockStat =:= recv_cnt; - SockStat =:= send_oct; - SockStat =:= send_cnt; - SockStat =:= send_pend -> - case rabbit_net:getstat(Sock, [SockStat]) of - {ok, [{_, N}]} when is_number(N) -> N; - _ -> 0 - end; -info_internal(state, State) -> info_internal(connection_state, State); -info_internal(garbage_collection, _State) -> - rabbit_misc:get_gc_info(self()); -info_internal(reductions, _State) -> - {reductions, Reductions} = erlang:process_info(self(), reductions), - Reductions; -info_internal(conn_name, #state{conn_name = Val}) -> - Val; -info_internal(connection_state, #state{received_connect_frame = false}) -> - starting; -info_internal(connection_state, #state{connection_state = Val}) -> - Val; -info_internal(connection, #state{connection = Val}) -> - Val; -info_internal(Key, #state{proc_state = ProcState}) -> - rabbit_mqtt_processor:info(Key, ProcState). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store.erl diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_dets.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_dets.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_dets.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_dets.erl diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_ets.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_ets.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_ets.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_retained_msg_store_ets.erl diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer.erl diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl similarity index 82% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl index 2f7cb17..17ee6d2 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_retainer_sup.erl @@ -39,13 +39,12 @@ start_child(VHost) when is_binary(VHost) -> start_child(RetainStoreMod, VHost) -> supervisor2:start_child(?MODULE, - - {vhost_to_atom(VHost), + {binary_to_atom(VHost, ?ENCODING), {rabbit_mqtt_retainer, start_link, [RetainStoreMod, VHost]}, permanent, 60, worker, [rabbit_mqtt_retainer]}). delete_child(VHost) -> - Id = vhost_to_atom(VHost), + Id = binary_to_atom(VHost, ?ENCODING), ok = supervisor2:terminate_child(?MODULE, Id), ok = supervisor2:delete_child(?MODULE, Id). @@ -56,14 +55,6 @@ init([]) -> {ok, {{one_for_one, 5, 5}, child_specs(Mod, rabbit_vhost:list())}}. child_specs(Mod, VHosts) -> - %% see start_child/2 - [{vhost_to_atom(V), + [{binary_to_atom(V, ?ENCODING), {rabbit_mqtt_retainer, start_link, [Mod, V]}, permanent, infinity, worker, [rabbit_mqtt_retainer]} || V <- VHosts]. - -vhost_to_atom(VHost) -> - %% we'd like to avoid any conversion here because - %% this atom isn't meant to be human-readable, only - %% unique. This makes sure we don't get noisy process restarts - %% with really unusual vhost names used by various HTTP API test suites - rabbit_data_coercion:to_atom(VHost, latin1). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl index 6b85285..6a43cb5 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_sup). diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl similarity index 89% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl index 2874f83..542b68e 100644 --- a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl +++ b/deps/rabbitmq_mqtt/src/rabbit_mqtt_util.erl @@ -11,23 +11,14 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_mqtt_util). -include("rabbit_mqtt.hrl"). --export([subcription_queue_name/1, - mqtt2amqp/1, - amqp2mqtt/1, - gen_client_id/0, - env/1, - table_lookup/2, - path_for/2, - path_for/3, - vhost_name_to_table_name/1 - ]). +-compile(export_all). subcription_queue_name(ClientId) -> Base = "mqtt-subscription-" ++ ClientId ++ "qos", diff --git a/rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_vhost_event_handler.erl b/deps/rabbitmq_mqtt/src/rabbit_mqtt_vhost_event_handler.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_mqtt/src/rabbit_mqtt_vhost_event_handler.erl rename to deps/rabbitmq_mqtt/src/rabbit_mqtt_vhost_event_handler.erl diff --git a/deps/rabbitmq_mqtt/src/rabbitmq_mqtt.app.src b/deps/rabbitmq_mqtt/src/rabbitmq_mqtt.app.src new file mode 100644 index 0000000..a579999 --- /dev/null +++ b/deps/rabbitmq_mqtt/src/rabbitmq_mqtt.app.src @@ -0,0 +1,25 @@ +{application, rabbitmq_mqtt, + [{description, "RabbitMQ MQTT Adapter"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_mqtt, []}}, + {env, [{default_user, <<"guest">>}, + {default_pass, <<"guest">>}, + {ssl_cert_login,false}, + %% To satisfy an unfortunate expectation from popular MQTT clients. + {allow_anonymous, true}, + {vhost, <<"/">>}, + {exchange, <<"amq.topic">>}, + {subscription_ttl, 86400000}, %% 24 hours + {retained_message_store, rabbit_mqtt_retained_msg_store_dets}, + %% only used by DETS store + {retained_message_store_dets_sync_interval, 2000}, + {prefetch, 10}, + {ssl_listeners, []}, + {num_ssl_acceptors, 1}, + {tcp_listeners, [1883]}, + {num_tcp_acceptors, 10}, + {tcp_listen_options, [{backlog, 128}, + {nodelay, true}]}]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, ranch, amqp_client]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/CODE_OF_CONDUCT.md b/deps/rabbitmq_recent_history_exchange/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/CODE_OF_CONDUCT.md rename to deps/rabbitmq_recent_history_exchange/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_sharding/CONTRIBUTING.md b/deps/rabbitmq_recent_history_exchange/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/CONTRIBUTING.md rename to deps/rabbitmq_recent_history_exchange/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/LICENSE.md b/deps/rabbitmq_recent_history_exchange/LICENSE.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/LICENSE.md rename to deps/rabbitmq_recent_history_exchange/LICENSE.md diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/Makefile b/deps/rabbitmq_recent_history_exchange/Makefile similarity index 65% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/Makefile rename to deps/rabbitmq_recent_history_exchange/Makefile index 41500df..ac7f04f 100644 --- a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/Makefile +++ b/deps/rabbitmq_recent_history_exchange/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_recent_history_exchange -PROJECT_DESCRIPTION = RabbitMQ Recent History Exchange DEPS = rabbit_common rabbit -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client +TEST_DEPS = rabbitmq_ct_helpers amqp_client -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/README.md b/deps/rabbitmq_recent_history_exchange/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/README.md rename to deps/rabbitmq_recent_history_exchange/README.md diff --git a/deps/rabbitmq_recent_history_exchange/erlang.mk b/deps/rabbitmq_recent_history_exchange/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_recent_history_exchange/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/etc/rabbit-hare.config b/deps/rabbitmq_recent_history_exchange/etc/rabbit-hare.config similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/etc/rabbit-hare.config rename to deps/rabbitmq_recent_history_exchange/etc/rabbit-hare.config diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/etc/rabbit-test.config b/deps/rabbitmq_recent_history_exchange/etc/rabbit-test.config similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/etc/rabbit-test.config rename to deps/rabbitmq_recent_history_exchange/etc/rabbit-test.config diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/include/rabbit_recent_history.hrl b/deps/rabbitmq_recent_history_exchange/include/rabbit_recent_history.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/include/rabbit_recent_history.hrl rename to deps/rabbitmq_recent_history_exchange/include/rabbit_recent_history.hrl diff --git a/deps/rabbitmq_recent_history_exchange/rabbitmq-components.mk b/deps/rabbitmq_recent_history_exchange/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_recent_history_exchange/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl b/deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl rename to deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl index 7e37827..7815a99 100644 --- a/rabbitmq-server/deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl +++ b/deps/rabbitmq_recent_history_exchange/src/rabbit_exchange_type_recent_history.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Delayed Message %% %% The Initial Developer of the Original Code is Pivotal Software, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_exchange_type_recent_history). diff --git a/deps/rabbitmq_recent_history_exchange/src/rabbitmq_recent_history_exchange.app.src b/deps/rabbitmq_recent_history_exchange/src/rabbitmq_recent_history_exchange.app.src new file mode 100644 index 0000000..658a6a2 --- /dev/null +++ b/deps/rabbitmq_recent_history_exchange/src/rabbitmq_recent_history_exchange.app.src @@ -0,0 +1,6 @@ +{application, rabbitmq_recent_history_exchange, + [{description, "RabbitMQ Recent History Exchange"}, + {vsn, "1.2.1"}, + {modules, []}, + {registered, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit, mnesia]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_sharding/CODE_OF_CONDUCT.md b/deps/rabbitmq_sharding/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/CODE_OF_CONDUCT.md rename to deps/rabbitmq_sharding/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_shovel/CONTRIBUTING.md b/deps/rabbitmq_sharding/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel/CONTRIBUTING.md rename to deps/rabbitmq_sharding/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_sharding/LICENSE b/deps/rabbitmq_sharding/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/LICENSE rename to deps/rabbitmq_sharding/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_sharding/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_sharding/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_sharding/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_sharding/LICENSE-MPL2 b/deps/rabbitmq_sharding/LICENSE-MPL2 similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/LICENSE-MPL2 rename to deps/rabbitmq_sharding/LICENSE-MPL2 diff --git a/rabbitmq-server/deps/rabbitmq_sharding/Makefile b/deps/rabbitmq_sharding/Makefile similarity index 65% rename from rabbitmq-server/deps/rabbitmq_sharding/Makefile rename to deps/rabbitmq_sharding/Makefile index e52f888..34a928f 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/Makefile +++ b/deps/rabbitmq_sharding/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_sharding -PROJECT_DESCRIPTION = RabbitMQ Sharding Plugin DEPS = rabbit_common rabbit -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers amqp_client +TEST_DEPS = rabbitmq_ct_helpers amqp_client -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_sharding/README.extra.md b/deps/rabbitmq_sharding/README.extra.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/README.extra.md rename to deps/rabbitmq_sharding/README.extra.md diff --git a/rabbitmq-server/deps/rabbitmq_sharding/README.md b/deps/rabbitmq_sharding/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/README.md rename to deps/rabbitmq_sharding/README.md diff --git a/rabbitmq-server/deps/rabbitmq_sharding/docs/sharded_queues.png b/deps/rabbitmq_sharding/docs/sharded_queues.png similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/docs/sharded_queues.png rename to deps/rabbitmq_sharding/docs/sharded_queues.png diff --git a/deps/rabbitmq_sharding/erlang.mk b/deps/rabbitmq_sharding/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_sharding/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_sharding/etc/rabbit-hare.config b/deps/rabbitmq_sharding/etc/rabbit-hare.config similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/etc/rabbit-hare.config rename to deps/rabbitmq_sharding/etc/rabbit-hare.config diff --git a/rabbitmq-server/deps/rabbitmq_sharding/etc/rabbit-test.config b/deps/rabbitmq_sharding/etc/rabbit-test.config similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/etc/rabbit-test.config rename to deps/rabbitmq_sharding/etc/rabbit-test.config diff --git a/rabbitmq-server/deps/rabbitmq_sharding/etc/rkey.sh b/deps/rabbitmq_sharding/etc/rkey.sh similarity index 100% rename from rabbitmq-server/deps/rabbitmq_sharding/etc/rkey.sh rename to deps/rabbitmq_sharding/etc/rkey.sh diff --git a/deps/rabbitmq_sharding/rabbitmq-components.mk b/deps/rabbitmq_sharding/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_sharding/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl index 18c83eb..f3f1921 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_decorator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_exchange_decorator). diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl index cf95a79..ebfa1d7 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_exchange_type_modulus_hash.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_exchange_type_modulus_hash). diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl index bd33a52..2001b68 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_interceptor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_interceptor). diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl index fa420f6..e1b139f 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_policy_validator.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_policy_validator). diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl index 3bcb9b9..da513aa 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_shard.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_shard). diff --git a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_util.erl b/deps/rabbitmq_sharding/src/rabbit_sharding_util.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_util.erl rename to deps/rabbitmq_sharding/src/rabbit_sharding_util.erl index 24f4027..4aa6a09 100644 --- a/rabbitmq-server/deps/rabbitmq_sharding/src/rabbit_sharding_util.erl +++ b/deps/rabbitmq_sharding/src/rabbit_sharding_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Sharding Plugin %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_sharding_util). diff --git a/deps/rabbitmq_sharding/src/rabbitmq_sharding.app.src b/deps/rabbitmq_sharding/src/rabbitmq_sharding.app.src new file mode 100644 index 0000000..8fb742a --- /dev/null +++ b/deps/rabbitmq_sharding/src/rabbitmq_sharding.app.src @@ -0,0 +1,6 @@ +{application, rabbitmq_sharding, + [{description, "RabbitMQ Sharding Plugin"}, + {vsn, "0.1.0"}, + {modules, []}, + {registered, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_shovel/CODE_OF_CONDUCT.md b/deps/rabbitmq_shovel/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel/CODE_OF_CONDUCT.md rename to deps/rabbitmq_shovel/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/CONTRIBUTING.md b/deps/rabbitmq_shovel/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/CONTRIBUTING.md rename to deps/rabbitmq_shovel/CONTRIBUTING.md diff --git a/deps/rabbitmq_shovel/Makefile b/deps/rabbitmq_shovel/Makefile new file mode 100644 index 0000000..1922956 --- /dev/null +++ b/deps/rabbitmq_shovel/Makefile @@ -0,0 +1,15 @@ +PROJECT = rabbitmq_shovel + +DEPS = rabbit_common rabbit amqp_client +TEST_DEPS = rabbitmq_ct_helpers + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_shovel/README.md b/deps/rabbitmq_shovel/README.md similarity index 92% rename from rabbitmq-server/deps/rabbitmq_shovel/README.md rename to deps/rabbitmq_shovel/README.md index 835f955..f2eb61a 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/README.md +++ b/deps/rabbitmq_shovel/README.md @@ -19,4 +19,4 @@ See [RabbitMQ shovel plugin](http://www.rabbitmq.com/shovel.html) on rabbitmq.co Released under [the same license as RabbitMQ](https://www.rabbitmq.com/mpl.html). -2007-2017 (c) Pivotal Software Inc. +2007-2016 (c) Pivotal Software Inc. diff --git a/deps/rabbitmq_shovel/erlang.mk b/deps/rabbitmq_shovel/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_shovel/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_shovel/include/rabbit_shovel.hrl b/deps/rabbitmq_shovel/include/rabbit_shovel.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel/include/rabbit_shovel.hrl rename to deps/rabbitmq_shovel/include/rabbit_shovel.hrl diff --git a/deps/rabbitmq_shovel/rabbitmq-components.mk b/deps/rabbitmq_shovel/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_shovel/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel.erl b/deps/rabbitmq_shovel/src/rabbit_shovel.erl similarity index 92% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel.erl index 82ae51a..a078db6 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_config.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_config.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_config.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_config.erl index 768ddd2..34e4315 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_config.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_config.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_config). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl similarity index 95% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl index 23fab1d..4dec9ea 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_dyn_worker_sup). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl index e2bf327..0f6ee87 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_dyn_worker_sup_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_dyn_worker_sup_sup). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl index 108e510..2cb4b60 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_parameters.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_parameters). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_status.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_status.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_status.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_status.erl index 978fdbc..41b6cef 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_status.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_status.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_status). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl index ede22cc..6463c9d 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_sup). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_util.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_util.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_util.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_util.erl index 2e72c2d..30a64b7 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_util.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_util). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl index 97754c5..f2660fc 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_worker.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_worker). diff --git a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl b/deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl rename to deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl index b974fb0..0c972ca 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl +++ b/deps/rabbitmq_shovel/src/rabbit_shovel_worker_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_worker_sup). diff --git a/deps/rabbitmq_shovel/src/rabbitmq_shovel.app.src b/deps/rabbitmq_shovel/src/rabbitmq_shovel.app.src new file mode 100644 index 0000000..40c538d --- /dev/null +++ b/deps/rabbitmq_shovel/src/rabbitmq_shovel.app.src @@ -0,0 +1,13 @@ +{application, rabbitmq_shovel, + [{description, "Data Shovel for RabbitMQ"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {env, [{defaults, [{prefetch_count, 1000}, + {ack_mode, on_confirm}, + {publish_fields, []}, + {publish_properties, []}, + {reconnect_delay, 5}] + }]}, + {mod, {rabbit_shovel, []}}, + {applications, [kernel, stdlib, rabbit_common, rabbit, amqp_client]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/CODE_OF_CONDUCT.md b/deps/rabbitmq_shovel_management/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/CODE_OF_CONDUCT.md rename to deps/rabbitmq_shovel_management/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_stomp/CONTRIBUTING.md b/deps/rabbitmq_shovel_management/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/CONTRIBUTING.md rename to deps/rabbitmq_shovel_management/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/Makefile b/deps/rabbitmq_shovel_management/Makefile similarity index 56% rename from rabbitmq-server/deps/rabbitmq_shovel_management/Makefile rename to deps/rabbitmq_shovel_management/Makefile index aa9d8c4..3c0aef0 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel_management/Makefile +++ b/deps/rabbitmq_shovel_management/Makefile @@ -1,10 +1,8 @@ PROJECT = rabbitmq_shovel_management -PROJECT_DESCRIPTION = Management extension for the Shovel plugin -DEPS = rabbit_common rabbit rabbitmq_management rabbitmq_shovel -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers +DEPS = rabbit_common rabbit rabbitmq_management rabbitmq_shovel webmachine +TEST_DEPS = rabbitmq_ct_helpers -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/README.md b/deps/rabbitmq_shovel_management/README.md similarity index 94% rename from rabbitmq-server/deps/rabbitmq_shovel_management/README.md rename to deps/rabbitmq_shovel_management/README.md index 7a658dc..7d68155 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel_management/README.md +++ b/deps/rabbitmq_shovel_management/README.md @@ -31,4 +31,4 @@ The HTTP API is very small: Released under [the same license as RabbitMQ](https://www.rabbitmq.com/mpl.html). -2007-2017 (c) Pivotal Software Inc. +2007-2016 (c) Pivotal Software Inc. diff --git a/deps/rabbitmq_shovel_management/erlang.mk b/deps/rabbitmq_shovel_management/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_shovel_management/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/shovel.js b/deps/rabbitmq_shovel_management/priv/www/js/shovel.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/shovel.js rename to deps/rabbitmq_shovel_management/priv/www/js/shovel.js diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovel.ejs b/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovel.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovel.ejs rename to deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovel.ejs diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovels.ejs b/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovels.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovels.ejs rename to deps/rabbitmq_shovel_management/priv/www/js/tmpl/dynamic-shovels.ejs diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/shovels.ejs b/deps/rabbitmq_shovel_management/priv/www/js/tmpl/shovels.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_shovel_management/priv/www/js/tmpl/shovels.ejs rename to deps/rabbitmq_shovel_management/priv/www/js/tmpl/shovels.ejs diff --git a/deps/rabbitmq_shovel_management/rabbitmq-components.mk b/deps/rabbitmq_shovel_management/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_shovel_management/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl b/deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl similarity index 89% rename from rabbitmq-server/deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl rename to deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl index eb027d5..27f0937 100644 --- a/rabbitmq-server/deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl +++ b/deps/rabbitmq_shovel_management/src/rabbit_shovel_mgmt.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_shovel_mgmt). @@ -19,28 +19,25 @@ -behaviour(rabbit_mgmt_extension). -export([dispatcher/0, web_ui/0]). --export([init/3, rest_init/2, to_json/2, resource_exists/2, content_types_provided/2, +-export([init/1, to_json/2, resource_exists/2, content_types_provided/2, is_authorized/2]). -import(rabbit_misc, [pget/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). -dispatcher() -> [{"/shovels", ?MODULE, []}, - {"/shovels/:vhost", ?MODULE, []}]. +dispatcher() -> [{["shovels"], ?MODULE, []}, + {["shovels", vhost], ?MODULE, []}]. web_ui() -> [{javascript, <<"shovel.js">>}]. %%-------------------------------------------------------------------- -init(_, _, _) -> - {upgrade, protocol, cowboy_rest}. - -rest_init(Req, _Opts) -> - {ok, Req, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. resource_exists(ReqData, Context) -> {case rabbit_mgmt_util:vhost(ReqData) of diff --git a/deps/rabbitmq_shovel_management/src/rabbitmq_shovel_management.app.src b/deps/rabbitmq_shovel_management/src/rabbitmq_shovel_management.app.src new file mode 100644 index 0000000..fc68911 --- /dev/null +++ b/deps/rabbitmq_shovel_management/src/rabbitmq_shovel_management.app.src @@ -0,0 +1,6 @@ +{application, rabbitmq_shovel_management, + [{description, "Shovel Status"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit, rabbitmq_management]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_stomp/CODE_OF_CONDUCT.md b/deps/rabbitmq_stomp/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/CODE_OF_CONDUCT.md rename to deps/rabbitmq_stomp/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_top/CONTRIBUTING.md b/deps/rabbitmq_stomp/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_top/CONTRIBUTING.md rename to deps/rabbitmq_stomp/CONTRIBUTING.md diff --git a/deps/rabbitmq_stomp/Makefile b/deps/rabbitmq_stomp/Makefile new file mode 100644 index 0000000..4d421e8 --- /dev/null +++ b/deps/rabbitmq_stomp/Makefile @@ -0,0 +1,15 @@ +PROJECT = rabbitmq_stomp + +DEPS = ranch rabbit_common rabbit amqp_client +TEST_DEPS = rabbitmq_ct_helpers + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_stomp/NOTES b/deps/rabbitmq_stomp/NOTES similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/NOTES rename to deps/rabbitmq_stomp/NOTES diff --git a/rabbitmq-server/deps/rabbitmq_stomp/README.md b/deps/rabbitmq_stomp/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/README.md rename to deps/rabbitmq_stomp/README.md diff --git a/deps/rabbitmq_stomp/erlang.mk b/deps/rabbitmq_stomp/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_stomp/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_recv.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_recv.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_recv.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_recv.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_client.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_client.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_client.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_client.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_service.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_service.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_service.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_rpc_service.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send_many.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send_many.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send_many.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_send_many.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_slow_recv.pl b/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_slow_recv.pl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_slow_recv.pl rename to deps/rabbitmq_stomp/examples/perl/rabbitmq_stomp_slow_recv.pl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-receiver.rb b/deps/rabbitmq_stomp/examples/ruby/cb-receiver.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-receiver.rb rename to deps/rabbitmq_stomp/examples/ruby/cb-receiver.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-sender.rb b/deps/rabbitmq_stomp/examples/ruby/cb-sender.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-sender.rb rename to deps/rabbitmq_stomp/examples/ruby/cb-sender.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-slow-receiver.rb b/deps/rabbitmq_stomp/examples/ruby/cb-slow-receiver.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/cb-slow-receiver.rb rename to deps/rabbitmq_stomp/examples/ruby/cb-slow-receiver.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/persistent-receiver.rb b/deps/rabbitmq_stomp/examples/ruby/persistent-receiver.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/persistent-receiver.rb rename to deps/rabbitmq_stomp/examples/ruby/persistent-receiver.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/persistent-sender.rb b/deps/rabbitmq_stomp/examples/ruby/persistent-sender.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/persistent-sender.rb rename to deps/rabbitmq_stomp/examples/ruby/persistent-sender.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-receiver.rb b/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-receiver.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-receiver.rb rename to deps/rabbitmq_stomp/examples/ruby/topic-broadcast-receiver.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-with-unsubscribe.rb b/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-with-unsubscribe.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-broadcast-with-unsubscribe.rb rename to deps/rabbitmq_stomp/examples/ruby/topic-broadcast-with-unsubscribe.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-sender.rb b/deps/rabbitmq_stomp/examples/ruby/topic-sender.rb similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/examples/ruby/topic-sender.rb rename to deps/rabbitmq_stomp/examples/ruby/topic-sender.rb diff --git a/rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp.hrl b/deps/rabbitmq_stomp/include/rabbit_stomp.hrl similarity index 67% rename from rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp.hrl rename to deps/rabbitmq_stomp/include/rabbit_stomp.hrl index 00b0612..455d310 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp.hrl +++ b/deps/rabbitmq_stomp/include/rabbit_stomp.hrl @@ -21,26 +21,3 @@ ssl_cert_login}). -define(SUPPORTED_VERSIONS, ["1.0", "1.1", "1.2"]). - --define(INFO_ITEMS, - [conn_name, - connection, - connection_state, - session_id, - channel, - version, - ssl_cert_login, - implicit_connect, - default_login, - default_passcode, - ssl_login_name, - peer_addr, - host, - port, - peer_host, - peer_port, - protocol, - channels, - channel_max, - frame_max, - client_properties]). diff --git a/rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp_frame.hrl b/deps/rabbitmq_stomp/include/rabbit_stomp_frame.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp_frame.hrl rename to deps/rabbitmq_stomp/include/rabbit_stomp_frame.hrl diff --git a/rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp_headers.hrl b/deps/rabbitmq_stomp/include/rabbit_stomp_headers.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_stomp/include/rabbit_stomp_headers.hrl rename to deps/rabbitmq_stomp/include/rabbit_stomp_headers.hrl diff --git a/deps/rabbitmq_stomp/rabbitmq-components.mk b/deps/rabbitmq_stomp/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_stomp/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp.erl b/deps/rabbitmq_stomp/src/rabbit_stomp.erl similarity index 85% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp.erl index 76463e9..d352a06 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp). @@ -20,8 +20,6 @@ -behaviour(application). -export([start/2, stop/1]). --export([parse_default_user/2]). --export([list/0]). -define(DEFAULT_CONFIGURATION, #stomp_configuration{ @@ -87,11 +85,3 @@ report_configuration(#stomp_configuration{ end, ok. - -list() -> - [Client - || {_, ListSupPid, _, _} <- supervisor2:which_children(rabbit_stomp_sup), - {_, RanchSup, supervisor, _} <- supervisor2:which_children(ListSupPid), - {ranch_conns_sup, ConnSup, _, _} <- supervisor:which_children(RanchSup), - {_, CliSup, _, _} <- supervisor:which_children(ConnSup), - {rabbit_stomp_reader, Client, _, _} <- supervisor:which_children(CliSup)]. diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl index 6691947..e972a57 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_client_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp_client_sup). diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl index 6b8b893..a24a164 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_frame.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% %% stomp_frame implements the STOMP framing protocol "version 1.0", as diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl similarity index 92% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl index 15ea68d..8fb68fa 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_processor.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp_processor). @@ -23,7 +23,6 @@ send_delivery/5]). -export([adapter_name/1]). --export([info/2]). -include_lib("amqp_client/include/amqp_client.hrl"). -include_lib("amqp_client/include/rabbit_routing_prefixes.hrl"). @@ -58,13 +57,13 @@ adapter_name(State) -> PeerAddr :: inet:ip_address(). -type process_frame_result() :: - {ok, term(), #proc_state{}} | + {ok, #proc_state{}} | {stop, term(), #proc_state{}}. -spec process_frame(#stomp_frame{}, #proc_state{}) -> process_frame_result(). --spec flush_and_die(#proc_state{}) -> #proc_state{}. +-spec flush_and_die(#proc_state{}) -> ok. -spec command({Command, Frame}, State) -> process_frame_result() when Command :: string(), @@ -106,30 +105,6 @@ process_frame(Frame = #stomp_frame{command = Command}, State) -> flush_and_die(State) -> close_connection(State). -info(session_id, #proc_state{session_id = Val}) -> - Val; -info(channel, #proc_state{channel = Val}) -> Val; -info(version, #proc_state{version = Val}) -> Val; -info(ssl_cert_login, #proc_state{config = #stomp_configuration{ssl_cert_login = Val}}) -> Val; -info(implicit_connect, #proc_state{config = #stomp_configuration{implicit_connect = Val}}) -> Val; -info(default_login, #proc_state{config = #stomp_configuration{default_login = Val}}) -> Val; -info(default_passcode, #proc_state{config = #stomp_configuration{default_passcode = Val}}) -> Val; -info(ssl_login_name, #proc_state{ssl_login_name = Val}) -> Val; -info(peer_addr, #proc_state{peer_addr = Val}) -> Val; -info(host, #proc_state{adapter_info = #amqp_adapter_info{host = Val}}) -> Val; -info(port, #proc_state{adapter_info = #amqp_adapter_info{port = Val}}) -> Val; -info(peer_host, #proc_state{adapter_info = #amqp_adapter_info{peer_host = Val}}) -> Val; -info(peer_port, #proc_state{adapter_info = #amqp_adapter_info{peer_port = Val}}) -> Val; -info(protocol, #proc_state{adapter_info = #amqp_adapter_info{protocol = Val}}) -> - case Val of - {Proto, Version} -> {Proto, rabbit_data_coercion:to_binary(Version)}; - Other -> Other - end; -info(channels, PState) -> additional_info(channels, PState); -info(channel_max, PState) -> additional_info(channel_max, PState); -info(frame_max, PState) -> additional_info(frame_max, PState); -info(client_properties, PState) -> additional_info(client_properties, PState). - initial_state(Configuration, {SendFun, AdapterInfo0 = #amqp_adapter_info{additional_info = Extra}, SSLLoginName, PeerAddr}) -> @@ -209,7 +184,7 @@ handle_exit(Conn, {shutdown, {connection_closing, State = #proc_state{connection = Conn}) -> amqp_death(Code, Explanation, State); handle_exit(Conn, Reason, State = #proc_state{connection = Conn}) -> - _ = send_error("AMQP connection died", "Reason: ~p", [Reason], State), + send_error("AMQP connection died", "Reason: ~p", [Reason], State), {stop, {conn_died, Reason}, State}; handle_exit(Ch, {shutdown, {server_initiated_close, Code, Explanation}}, @@ -217,7 +192,7 @@ handle_exit(Ch, {shutdown, {server_initiated_close, Code, Explanation}}, amqp_death(Code, Explanation, State); handle_exit(Ch, Reason, State = #proc_state{channel = Ch}) -> - _ = send_error("AMQP channel died", "Reason: ~p", [Reason], State), + send_error("AMQP channel died", "Reason: ~p", [Reason], State), {stop, {channel_died, Reason}, State}; handle_exit(Ch, {shutdown, {server_initiated_close, Code, Explanation}}, State = #proc_state{channel = Ch}) -> @@ -229,7 +204,7 @@ process_request(ProcessFun, State) -> process_request(ProcessFun, fun (StateM) -> StateM end, State). -process_request(ProcessFun, SuccessFun, State) -> +process_request(ProcessFun, SuccessFun, State=#proc_state{connection=Conn}) -> Res = case catch ProcessFun(State) of {'EXIT', {{shutdown, @@ -242,13 +217,13 @@ process_request(ProcessFun, SuccessFun, State) -> Result end, case Res of - {ok, Frame, NewState = #proc_state{connection = Conn}} -> - _ = case Frame of - none -> ok; - _ -> send_frame(Frame, NewState) - end, + {ok, Frame, NewState} -> + case Frame of + none -> ok; + _ -> send_frame(Frame, NewState) + end, {ok, SuccessFun(NewState), Conn}; - {error, Message, Detail, NewState = #proc_state{connection = Conn}} -> + {error, Message, Detail, NewState} -> {ok, send_error(Message, Detail, NewState), Conn}; {stop, normal, NewState} -> {stop, normal, SuccessFun(NewState)}; @@ -294,7 +269,7 @@ process_connect(Implicit, Frame, creds(_, _, #stomp_configuration{default_login = DefLogin, default_passcode = DefPasscode, force_default_creds = true}) -> - {iolist_to_binary(DefLogin), iolist_to_binary(DefPasscode)}; + {DefLogin, DefPasscode}; creds(Frame, SSLLoginName, #stomp_configuration{default_login = DefLogin, default_passcode = DefPasscode}) -> @@ -442,14 +417,14 @@ server_cancel_consumer(ConsumerTag, State = #proc_state{subscriptions = Subs}) - {ok, {_, Id1}} -> Id1; {error, {_, Id1}} -> "Unknown[" ++ Id1 ++ "]" end, - _ = send_error_frame("Server cancelled subscription", - [{?HEADER_SUBSCRIPTION, Id}], - "The server has canceled a subscription.~n" - "No more messages will be delivered for ~p.~n", - [Description], - State), + send_error_frame("Server cancelled subscription", + [{?HEADER_SUBSCRIPTION, Id}], + "The server has canceled a subscription.~n" + "No more messages will be delivered for ~p.~n", + [Description], + State), tidy_canceled_subscription(ConsumerTag, Subscription, - undefined, State) + #stomp_frame{}, State) end. cancel_subscription({error, invalid_prefix}, _Frame, State) -> @@ -488,15 +463,6 @@ cancel_subscription({ok, ConsumerTag, Description}, Frame, end end. -%% Server-initiated cancelations will pass an undefined instead of a -%% STOMP frame. In this case we know that the queue was deleted and -%% thus we don't have to clean it up. -tidy_canceled_subscription(ConsumerTag, _Subscription, - undefined, State = #proc_state{subscriptions = Subs}) -> - Subs1 = dict:erase(ConsumerTag, Subs), - ok(State#proc_state{subscriptions = Subs1}); - -%% Client-initiated cancelations will pass an actual frame tidy_canceled_subscription(ConsumerTag, #subscription{dest_hdr = DestHdr}, Frame, State = #proc_state{subscriptions = Subs}) -> Subs1 = dict:erase(ConsumerTag, Subs), @@ -639,7 +605,7 @@ start_connection(Params, Username, Addr) -> end. server_header() -> - {ok, Product} = application:get_key(rabbit, description), + {ok, Product} = application:get_key(rabbit, id), {ok, Version} = application:get_key(rabbit, vsn), rabbit_misc:format("~s/~s", [Product, Version]). @@ -664,8 +630,8 @@ do_subscribe(Destination, DestHdr, Frame, {ok, _} -> Message = "Duplicated subscription identifier", Detail = "A subscription identified by '~s' alredy exists.", - _ = error(Message, Detail, [ConsumerTag], State), - _ = send_error(Message, Detail, [ConsumerTag], State), + error(Message, Detail, [ConsumerTag], State), + send_error(Message, Detail, [ConsumerTag], State), {stop, normal, close_connection(State)}; error -> ExchangeAndKey = @@ -1034,7 +1000,7 @@ ensure_heartbeats(Heartbeats) -> {SendTimeout, ReceiveTimeout} = {millis_to_seconds(CY), millis_to_seconds(CX)}, - _ = rabbit_stomp_reader:start_heartbeats(self(), {SendTimeout, ReceiveTimeout}), + rabbit_stomp_reader:start_heartbeats(self(), {SendTimeout, ReceiveTimeout}), {SendTimeout * 1000 , ReceiveTimeout * 1000}. millis_to_seconds(M) when M =< 0 -> 0; @@ -1146,7 +1112,3 @@ send_error(Message, Detail, State) -> send_error(Message, Format, Args, State) -> send_error(Message, rabbit_misc:format(Format, Args), State). -additional_info(Key, - #proc_state{adapter_info = - #amqp_adapter_info{additional_info = AddInfo}}) -> - proplists:get_value(Key, AddInfo). diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl similarity index 79% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl index 5e079f0..d56a1fe 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_reader.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp_reader). @@ -22,22 +22,14 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]). -export([start_heartbeats/2]). --export([info/2]). -include("rabbit_stomp.hrl"). -include("rabbit_stomp_frame.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). --define(SIMPLE_METRICS, [pid, recv_oct, send_oct, reductions]). --define(OTHER_METRICS, [recv_cnt, send_cnt, send_pend, garbage_collection, state, - timeout]). - -record(reader_state, {socket, conn_name, parse_state, processor_state, state, conserve_resources, recv_outstanding, stats_timer, - parent, connection, heartbeat_sup, heartbeat, - timeout_sec %% heartbeat timeout value used, 0 means - %% heartbeats are disabled - }). + parent, connection, heartbeat_sup, heartbeat}). %%---------------------------------------------------------------------------- @@ -52,22 +44,15 @@ start_link(SupHelperPid, Ref, Sock, Configuration) -> %% meaningless synchronous call to the underlying gen_event %% mechanism. When it returns the mailbox is drained, and we %% return to our caller to accept more connections. - _ = gen_event:which_handlers(error_logger), + gen_event:which_handlers(error_logger), {ok, Pid}. log(Level, Fmt, Args) -> rabbit_log:log(connection, Level, Fmt, Args). -info(Pid, InfoItems) -> - case InfoItems -- ?INFO_ITEMS of - [] -> - gen_server2:call(Pid, {info, InfoItems}); - UnknownItems -> throw({bad_argument, UnknownItems}) - end. - init([SupHelperPid, Ref, Sock, Configuration]) -> process_flag(trap_exit, true), - rabbit_networking:accept_ack(Ref, Sock), + rabbit_net:accept_ack(Ref, Sock), case rabbit_net:connection_string(Sock, inbound) of {ok, ConnStr} -> @@ -79,7 +64,7 @@ init([SupHelperPid, Ref, Sock, Configuration]) -> [self(), ConnStr]), ParseState = rabbit_stomp_frame:initial_state(), - _ = register_resource_alarm(), + register_resource_alarm(), gen_server2:enter_loop(?MODULE, [], rabbit_event:init_stats_timer( run_socket(control_throttle( @@ -93,6 +78,9 @@ init([SupHelperPid, Ref, Sock, Configuration]) -> conserve_resources = false, recv_outstanding = false})), #reader_state.stats_timer), {backoff, 1000, 1000, 10000}); + {network_error, Reason} -> + rabbit_net:fast_close(Sock), + terminate({shutdown, Reason}, undefined); {error, enotconn} -> rabbit_net:fast_close(Sock), terminate(shutdown, undefined); @@ -102,13 +90,6 @@ init([SupHelperPid, Ref, Sock, Configuration]) -> end. -handle_call({info, InfoItems}, _From, State) -> - Infos = lists:map( - fun(InfoItem) -> - {InfoItem, info_internal(InfoItem, State)} - end, - InfoItems), - {reply, Infos, State}; handle_call(Msg, From, State) -> {stop, {stomp_unexpected_call, Msg, From}, State}. @@ -182,7 +163,7 @@ handle_info(#'basic.cancel'{consumer_tag = Ctag}, State) -> end; handle_info({start_heartbeats, {0, 0}}, State) -> - {noreply, State#reader_state{timeout_sec = {0, 0}}}; + {noreply, State}; handle_info({start_heartbeats, {SendTimeout, ReceiveTimeout}}, State = #reader_state{heartbeat_sup = SupPid, socket = Sock}) -> @@ -192,8 +173,7 @@ handle_info({start_heartbeats, {SendTimeout, ReceiveTimeout}}, ReceiveFun = fun() -> gen_server2:cast(Pid, client_timeout) end, Heartbeat = rabbit_heartbeat:start(SupPid, Sock, SendTimeout, SendFun, ReceiveTimeout, ReceiveFun), - {noreply, State#reader_state{heartbeat = Heartbeat, - timeout_sec = {SendTimeout, ReceiveTimeout}}}; + {noreply, State#reader_state{heartbeat = Heartbeat}}; %%---------------------------------------------------------------------------- @@ -271,18 +251,15 @@ run_socket(State = #reader_state{state = blocked}) -> run_socket(State = #reader_state{recv_outstanding = true}) -> State; run_socket(State = #reader_state{socket = Sock}) -> - _ = rabbit_net:async_recv(Sock, 0, infinity), + rabbit_net:async_recv(Sock, 0, infinity), State#reader_state{recv_outstanding = true}. -terminate(Reason, undefined) -> - log_reason(Reason, undefined), - {stop, Reason}; terminate(Reason, State = #reader_state{ processor_state = ProcState }) -> maybe_emit_stats(State), log_reason(Reason, State), - _ = rabbit_stomp_processor:flush_and_die(ProcState), - {stop, Reason}. + rabbit_stomp_processor:flush_and_die(ProcState), + ok. code_change(_OldVsn, State, _Extra) -> {ok, State}. @@ -330,14 +307,12 @@ log_reason({shutdown, client_heartbeat_timeout}, log_reason(normal, #reader_state{ conn_name = ConnName}) -> log(info, "closing STOMP connection ~p (~s)~n", [self(), ConnName]); -log_reason(shutdown, undefined) -> - log(error, "closing STOMP connection that never completed connection handshake (negotiation)~n", []); - log_reason(Reason, #reader_state{ processor_state = ProcState }) -> AdapterName = rabbit_stomp_processor:adapter_name(ProcState), rabbit_log:warning("STOMP connection ~s terminated" " with reason ~p, closing it~n", [AdapterName, Reason]). + %%---------------------------------------------------------------------------- processor_args(Configuration, Sock) -> @@ -381,18 +356,14 @@ maybe_emit_stats(State) -> rabbit_event:if_enabled(State, #reader_state.stats_timer, fun() -> emit_stats(State) end). -emit_stats(State=#reader_state{connection = C}) when C == none; C == undefined -> - %% Avoid emitting stats on terminate when the connection has not yet been - %% established, as this causes orphan entries on the stats database - State1 = rabbit_event:reset_stats_timer(State, #reader_state.stats_timer), - ensure_stats_timer(State1); -emit_stats(State) -> - [{_, Pid}, {_, Recv_oct}, {_, Send_oct}, {_, Reductions}] = I - = infos(?SIMPLE_METRICS, State), - Infos = infos(?OTHER_METRICS, State), - rabbit_core_metrics:connection_stats(Pid, Infos), - rabbit_core_metrics:connection_stats(Pid, Recv_oct, Send_oct, Reductions), - rabbit_event:notify(connection_stats, Infos ++ I), +emit_stats(State=#reader_state{socket = Sock, state = ConnState, connection = Conn}) -> + SockInfos = case rabbit_net:getstat(Sock, + [recv_oct, recv_cnt, send_oct, send_cnt, send_pend]) of + {ok, SI} -> SI; + {error, _} -> [] + end, + Infos = [{pid, Conn}, {state, ConnState} | SockInfos], + rabbit_event:notify(connection_stats, Infos), State1 = rabbit_event:reset_stats_timer(State, #reader_state.stats_timer), ensure_stats_timer(State1). @@ -405,36 +376,3 @@ ensure_stats_timer(State = #reader_state{}) -> processor_state(#reader_state{ processor_state = ProcState }) -> ProcState. processor_state(ProcState, #reader_state{} = State) -> State#reader_state{ processor_state = ProcState}. - -%%---------------------------------------------------------------------------- - -infos(Items, State) -> [{Item, info_internal(Item, State)} || Item <- Items]. - -info_internal(pid, State) -> info_internal(connection, State); -info_internal(SockStat, #reader_state{socket = Sock}) when SockStat =:= recv_oct; - SockStat =:= recv_cnt; - SockStat =:= send_oct; - SockStat =:= send_cnt; - SockStat =:= send_pend -> - case rabbit_net:getstat(Sock, [SockStat]) of - {ok, [{_, N}]} when is_number(N) -> N; - _ -> 0 - end; -info_internal(state, State) -> info_internal(connection_state, State); -info_internal(garbage_collection, _State) -> - rabbit_misc:get_gc_info(self()); -info_internal(reductions, _State) -> - {reductions, Reductions} = erlang:process_info(self(), reductions), - Reductions; -info_internal(timeout, #reader_state{timeout_sec = {_, Receive}}) -> - Receive; -info_internal(timeout, #reader_state{timeout_sec = undefined}) -> - 0; -info_internal(conn_name, #reader_state{conn_name = Val}) -> - rabbit_data_coercion:to_binary(Val); -info_internal(connection, #reader_state{connection = Val}) -> - Val; -info_internal(connection_state, #reader_state{state = Val}) -> - Val; -info_internal(Key, #reader_state{processor_state = ProcState}) -> - rabbit_stomp_processor:info(Key, ProcState). diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl similarity index 97% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl index e8b024b..817fc2a 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp_sup). diff --git a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_util.erl b/deps/rabbitmq_stomp/src/rabbit_stomp_util.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_util.erl rename to deps/rabbitmq_stomp/src/rabbit_stomp_util.erl index 2d794f7..e9bf6e4 100644 --- a/rabbitmq-server/deps/rabbitmq_stomp/src/rabbit_stomp_util.erl +++ b/deps/rabbitmq_stomp/src/rabbit_stomp_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_stomp_util). @@ -374,9 +374,7 @@ subscription_queue_name(Destination, SubscriptionId, Frame) -> %% AMQP queue names. It doesn't need to be secure; we use md5 here %% simply as a convenient means to bound the length. rabbit_guid:string( - erlang:md5( - term_to_binary_compat:term_to_binary_1( - {Destination, SubscriptionId})), + erlang:md5(term_to_binary({Destination, SubscriptionId})), "stomp-subscription"); Name -> Name @@ -385,6 +383,7 @@ subscription_queue_name(Destination, SubscriptionId, Frame) -> %% ---- Helpers ---- split([], _Splitter) -> []; +split(Content, []) -> Content; split(Content, Splitter) -> split(Content, [], [], Splitter). split([], RPart, RParts, _Splitter) -> diff --git a/deps/rabbitmq_stomp/src/rabbitmq_stomp.app.src b/deps/rabbitmq_stomp/src/rabbitmq_stomp.app.src new file mode 100644 index 0000000..444cec0 --- /dev/null +++ b/deps/rabbitmq_stomp/src/rabbitmq_stomp.app.src @@ -0,0 +1,23 @@ +{application, rabbitmq_stomp, + [{description, "RabbitMQ STOMP plugin"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_stomp, []}}, + {env, [{default_user, + [{login, <<"guest">>}, + {passcode, <<"guest">>}]}, + {default_vhost, <<"/">>}, + {ssl_cert_login, false}, + {implicit_connect, false}, + {tcp_listeners, [61613]}, + {num_tcp_acceptors, 10}, + {ssl_listeners, []}, + {num_ssl_acceptors, 1}, + {tcp_listen_options, [{backlog, 128}, + {nodelay, true}]}, + %% see rabbitmq/rabbitmq-stomp#39 + {trailing_lf, true}, + %% see rabbitmq/rabbitmq-stomp#57 + {hide_server_info, false}]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, amqp_client]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_top/CODE_OF_CONDUCT.md b/deps/rabbitmq_top/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_top/CODE_OF_CONDUCT.md rename to deps/rabbitmq_top/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_tracing/CONTRIBUTING.md b/deps/rabbitmq_top/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/CONTRIBUTING.md rename to deps/rabbitmq_top/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_top/Makefile b/deps/rabbitmq_top/Makefile similarity index 74% rename from rabbitmq-server/deps/rabbitmq_top/Makefile rename to deps/rabbitmq_top/Makefile index ac860cb..c15576e 100644 --- a/rabbitmq-server/deps/rabbitmq_top/Makefile +++ b/deps/rabbitmq_top/Makefile @@ -1,10 +1,7 @@ PROJECT = rabbitmq_top -PROJECT_DESCRIPTION = RabbitMQ Top -PROJECT_MOD = rabbit_top_app DEPS = rabbit_common rabbit amqp_client rabbitmq_management -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/rabbitmq-server/deps/rabbitmq_top/README.md b/deps/rabbitmq_top/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_top/README.md rename to deps/rabbitmq_top/README.md diff --git a/deps/rabbitmq_top/erlang.mk b/deps/rabbitmq_top/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_top/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/ets_tables.ejs b/deps/rabbitmq_top/priv/www/js/tmpl/ets_tables.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/ets_tables.ejs rename to deps/rabbitmq_top/priv/www/js/tmpl/ets_tables.ejs diff --git a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/process.ejs b/deps/rabbitmq_top/priv/www/js/tmpl/process.ejs similarity index 89% rename from rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/process.ejs rename to deps/rabbitmq_top/priv/www/js/tmpl/process.ejs index 7ecec56..a567c6e 100644 --- a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/process.ejs +++ b/deps/rabbitmq_top/priv/www/js/tmpl/process.ejs @@ -18,10 +18,6 @@ Message queue length <%= process.message_queue_len %> - - Internal buffer -
<%= process.buffer_len %>
- Reductions / sec <%= fmt_reduction_delta(process.reduction_delta) %> diff --git a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs b/deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs similarity index 91% rename from rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs rename to deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs index 5c8e0d1..ed863f2 100644 --- a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs +++ b/deps/rabbitmq_top/priv/www/js/tmpl/processes.ejs @@ -30,7 +30,6 @@ <%= fmt_sort('Memory', 'memory') %> <%= fmt_sort('Reductions / sec', 'reduction_delta') %> Message queue - Internal buffer Status @@ -46,7 +45,6 @@ <%= fmt_bytes(process.memory * 1.0) %> <%= fmt_reduction_delta(process.reduction_delta) %> <%= process.message_queue_len %> - <%= process.buffer_len %> <%= process.status %> <% } %> diff --git a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/top.js b/deps/rabbitmq_top/priv/www/js/top.js similarity index 87% rename from rabbitmq-server/deps/rabbitmq_top/priv/www/js/top.js rename to deps/rabbitmq_top/priv/www/js/top.js index 8cf34e1..c5c4225 100644 --- a/rabbitmq-server/deps/rabbitmq_top/priv/www/js/top.js +++ b/deps/rabbitmq_top/priv/www/js/top.js @@ -30,16 +30,12 @@ dispatcher_add(function(sammy) { NAVIGATION['Admin'][0]['Top Processes'] = ['#/top', 'administrator']; NAVIGATION['Admin'][0]['Top ETS Tables'] = ['#/top/ets', 'administrator']; -HELP['process-internal-buffer'] = "Some processes drain their Erlang process mailbox (Erlang message queue) into a separate priority queue. \"Queue\" here refers to a data structure and should not be confused with RabbitMQ queues."; - $('select#top-node').live('change', function() { - var url='#/top/' + $(this).val() + "/" + $('select#row-count').val(); - go_to(url); + go_to('#/top/' + $(this).val()); }); $('select#top-node-ets').live('change', function() { - var url='#/top/ets/' + $(this).val() + "/" + $('select#row-count-ets').val(); - go_to(url); + go_to('#/top/ets' + $(this).val()); }); $('select#row-count').live('change', function() { diff --git a/deps/rabbitmq_top/rabbitmq-components.mk b/deps/rabbitmq_top/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_top/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_app.erl b/deps/rabbitmq_top/src/rabbit_top_app.erl similarity index 92% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_app.erl rename to deps/rabbitmq_top/src/rabbit_top_app.erl index 065b398..a1e7e96 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_app.erl +++ b/deps/rabbitmq_top/src/rabbit_top_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is VMware, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_top_app). diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_extension.erl b/deps/rabbitmq_top/src/rabbit_top_extension.erl similarity index 79% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_extension.erl rename to deps/rabbitmq_top/src/rabbit_top_extension.erl index 5b5388a..b45b088 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_extension.erl +++ b/deps/rabbitmq_top/src/rabbit_top_extension.erl @@ -20,7 +20,7 @@ -export([dispatcher/0, web_ui/0]). -dispatcher() -> [{"/top/:node", rabbit_top_wm_processes, []}, - {"/top/ets/:node", rabbit_top_wm_ets_tables, []}, - {"/process/:pid", rabbit_top_wm_process, []}]. +dispatcher() -> [{["top", node], rabbit_top_wm_processes, []}, + {["top", "ets", node], rabbit_top_wm_ets_tables, []}, + {["process", pid], rabbit_top_wm_process, []}]. web_ui() -> [{javascript, <<"top.js">>}]. diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_sup.erl b/deps/rabbitmq_top/src/rabbit_top_sup.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_sup.erl rename to deps/rabbitmq_top/src/rabbit_top_sup.erl diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_util.erl b/deps/rabbitmq_top/src/rabbit_top_util.erl similarity index 82% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_util.erl rename to deps/rabbitmq_top/src/rabbit_top_util.erl index 4371459..225c09f 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_util.erl +++ b/deps/rabbitmq_top/src/rabbit_top_util.erl @@ -19,7 +19,6 @@ -include_lib("rabbit_common/include/rabbit.hrl"). -export([toplist/3, fmt_all/1, fmt/1, obtain_name/1, safe_process_info/2]). --export([sort_by_param/2, sort_order_param/1, row_count_param/2]). toplist(Key, Count, List) -> Sorted = lists:sublist( @@ -31,24 +30,6 @@ toplist(Key, Info) -> {Key, Val} = lists:keyfind(Key, 1, Info), {Val, Info}. -sort_by_param(ReqData, Default) -> - case cowboy_req:qs_val(<<"sort">>, ReqData) of - {undefined, _} -> Default; - {Bin, _} -> rabbit_data_coercion:to_atom(Bin) - end. - -sort_order_param(ReqData) -> - case cowboy_req:qs_val(<<"sort_reverse">>, ReqData) of - {<<"true">>, _} -> asc; - _ -> desc - end. - -row_count_param(ReqData, Default) -> - case cowboy_req:qs_val(<<"row_count">>, ReqData) of - {undefined, _} -> Default; - {Bin, _} -> rabbit_data_coercion:to_integer(Bin) - end. - add_name(Info) -> {pid, Pid} = lists:keyfind(pid, 1, Info), [{name, obtain_name(Pid)} | Info]. @@ -141,10 +122,10 @@ initial_call_dict(Pid) -> fail end. -guess_initial_call({supervisor, _F, _A}) -> supervisor; -guess_initial_call({supervisor2, _F, _A}) -> supervisor; -guess_initial_call({cowboy_protocol, _F, _A}) -> cowboy_protocol; -guess_initial_call(_MFA) -> fail. +guess_initial_call({supervisor, _F, _A}) -> supervisor; +guess_initial_call({supervisor2, _F, _A}) -> supervisor; +guess_initial_call({mochiweb_acceptor, _F, _A}) -> mochiweb_http; +guess_initial_call(_MFA) -> fail. safe_process_info(Pid, Info) -> diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl b/deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl similarity index 61% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl rename to deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl index 65ec80f..8b38a97 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl +++ b/deps/rabbitmq_top/src/rabbit_top_wm_ets_tables.erl @@ -16,27 +16,33 @@ -module(rabbit_top_wm_ets_tables). --export([init/3]). --export([rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. to_json(ReqData, Context) -> - Sort = rabbit_top_util:sort_by_param(ReqData, memory), - Node = rabbit_data_coercion:to_atom(rabbit_mgmt_util:id(node, ReqData)), - Order = rabbit_top_util:sort_order_param(ReqData), - RowCount = rabbit_top_util:row_count_param(ReqData, 20), - + Sort = case wrq:get_qs_value("sort", ReqData) of + undefined -> memory; + Str -> list_to_atom(Str) + end, + Node = b2a(rabbit_mgmt_util:id(node, ReqData)), + Order = case wrq:get_qs_value("sort_reverse", ReqData) of + "true" -> asc; + _ -> desc + end, + RowCount = case wrq:get_qs_value("row_count", ReqData) of + undefined -> 20; + List when is_list(List) -> list_to_integer(List) + end, rabbit_mgmt_util:reply([{node, Node}, {row_count, RowCount}, {ets_tables, ets_tables(Node, Sort, Order, RowCount)}], @@ -47,13 +53,10 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- +b2a(B) -> list_to_atom(binary_to_list(B)). + ets_tables(Node, Sort, Order, RowCount) -> - try - [fmt(P) || P <- rabbit_top_worker:ets_tables(Node, Sort, Order, RowCount)] - catch - exit:{noproc, _} -> - [] - end. + [fmt(P) || P <- rabbit_top_worker:ets_tables(Node, Sort, Order, RowCount)]. fmt(Info) -> {owner, Pid} = lists:keyfind(owner, 1, Info), diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_process.erl b/deps/rabbitmq_top/src/rabbit_top_wm_process.erl similarity index 88% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_process.erl rename to deps/rabbitmq_top/src/rabbit_top_wm_process.erl index 1260c00..17a893d 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_process.erl +++ b/deps/rabbitmq_top/src/rabbit_top_wm_process.erl @@ -16,24 +16,22 @@ -module(rabbit_top_wm_process). --export([init/3]). --export([rest_init/2, to_json/2, resource_exists/2, content_types_provided/2, +-export([init/1, to_json/2, resource_exists/2, content_types_provided/2, is_authorized/2]). -define(ADDITIONAL_INFO, [current_stacktrace, trap_exit, links, monitors, monitored_by]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. to_json(ReqData, Context) -> rabbit_mgmt_util:reply(proc(ReqData), ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_processes.erl b/deps/rabbitmq_top/src/rabbit_top_wm_processes.erl similarity index 62% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_processes.erl rename to deps/rabbitmq_top/src/rabbit_top_wm_processes.erl index c93c833..4695c0a 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_wm_processes.erl +++ b/deps/rabbitmq_top/src/rabbit_top_wm_processes.erl @@ -16,27 +16,33 @@ -module(rabbit_top_wm_processes). --export([init/3]). --export([rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). -include_lib("amqp_client/include/amqp_client.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. to_json(ReqData, Context) -> - Sort = rabbit_top_util:sort_by_param(ReqData, reduction_delta), - Node = rabbit_data_coercion:to_atom(rabbit_mgmt_util:id(node, ReqData)), - Order = rabbit_top_util:sort_order_param(ReqData), - RowCount = rabbit_top_util:row_count_param(ReqData, 20), - + Sort = case wrq:get_qs_value("sort", ReqData) of + undefined -> reduction_delta; + Str -> list_to_atom(Str) + end, + Node = b2a(rabbit_mgmt_util:id(node, ReqData)), + Order = case wrq:get_qs_value("sort_reverse", ReqData) of + "true" -> asc; + _ -> desc + end, + RowCount = case wrq:get_qs_value("row_count", ReqData) of + undefined -> 20; + List when is_list(List) -> list_to_integer(List) + end, rabbit_mgmt_util:reply([{node, Node}, {row_count, RowCount}, {processes, procs(Node, Sort, Order, RowCount)}], @@ -47,13 +53,10 @@ is_authorized(ReqData, Context) -> %%-------------------------------------------------------------------- +b2a(B) -> list_to_atom(binary_to_list(B)). + procs(Node, Sort, Order, RowCount) -> - try - [fmt(P) || P <- rabbit_top_worker:procs(Node, Sort, Order, RowCount)] - catch - exit:{noproc, _} -> - [] - end. + [fmt(P) || P <- rabbit_top_worker:procs(Node, Sort, Order, RowCount)]. fmt(Info) -> {pid, Pid} = lists:keyfind(pid, 1, Info), diff --git a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_worker.erl b/deps/rabbitmq_top/src/rabbit_top_worker.erl similarity index 92% rename from rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_worker.erl rename to deps/rabbitmq_top/src/rabbit_top_worker.erl index c4ee561..d61a47c 100644 --- a/rabbitmq-server/deps/rabbitmq_top/src/rabbit_top_worker.erl +++ b/deps/rabbitmq_top/src/rabbit_top_worker.erl @@ -102,9 +102,8 @@ procs(OldProcs) -> {ok, OldProps} -> reductions(OldProps); error -> 0 end) div ?EVERY, - NewProps = expand_gen_server2_info( - Pid, [{reduction_delta, Delta} | Props]), - dict:store(Pid, NewProps, Procs) + dict:store( + Pid, [{reduction_delta, Delta} | Props], Procs) end end, dict:new(), processes()). @@ -162,12 +161,4 @@ bytes(Words) -> try Words * erlang:system_info(wordsize) catch _:_ -> 0 - end. - -expand_gen_server2_info(Pid, Props) -> - case rabbit_core_metrics:get_gen_server2_stats(Pid) of - not_found -> - Props; - BufferLength -> - [{buffer_len, BufferLength} | Props] - end. + end. \ No newline at end of file diff --git a/deps/rabbitmq_top/src/rabbitmq_top.app.src b/deps/rabbitmq_top/src/rabbitmq_top.app.src new file mode 100644 index 0000000..03a84e2 --- /dev/null +++ b/deps/rabbitmq_top/src/rabbitmq_top.app.src @@ -0,0 +1,7 @@ +{application, rabbitmq_top, + [{description, "RabbitMQ Top"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_top_app, []}}, + {applications, [kernel, stdlib, rabbit_common, rabbit, rabbitmq_management]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_tracing/CODE_OF_CONDUCT.md b/deps/rabbitmq_tracing/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/CODE_OF_CONDUCT.md rename to deps/rabbitmq_tracing/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_trust_store/CONTRIBUTING.md b/deps/rabbitmq_tracing/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_trust_store/CONTRIBUTING.md rename to deps/rabbitmq_tracing/CONTRIBUTING.md diff --git a/deps/rabbitmq_tracing/Makefile b/deps/rabbitmq_tracing/Makefile new file mode 100644 index 0000000..63b1c99 --- /dev/null +++ b/deps/rabbitmq_tracing/Makefile @@ -0,0 +1,15 @@ +PROJECT = rabbitmq_tracing + +DEPS = rabbit_common rabbit rabbitmq_management webmachine +TEST_DEPS = rabbitmq_ct_helpers + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_tracing/README.md b/deps/rabbitmq_tracing/README.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/README.md rename to deps/rabbitmq_tracing/README.md diff --git a/deps/rabbitmq_tracing/erlang.mk b/deps/rabbitmq_tracing/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_tracing/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/rabbitmq-server/deps/rabbitmq_tracing/priv/www/js/tmpl/traces.ejs b/deps/rabbitmq_tracing/priv/www/js/tmpl/traces.ejs similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/priv/www/js/tmpl/traces.ejs rename to deps/rabbitmq_tracing/priv/www/js/tmpl/traces.ejs diff --git a/rabbitmq-server/deps/rabbitmq_tracing/priv/www/js/tracing.js b/deps/rabbitmq_tracing/priv/www/js/tracing.js similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/priv/www/js/tracing.js rename to deps/rabbitmq_tracing/priv/www/js/tracing.js diff --git a/deps/rabbitmq_tracing/rabbitmq-components.mk b/deps/rabbitmq_tracing/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_tracing/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_app.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_app.erl similarity index 92% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_app.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_app.erl index cbb949b..4f0a29d 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_app.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_app). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl similarity index 99% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl index 58d18f2..d716497 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_consumer.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_consumer). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl similarity index 94% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl index 5dea3ab..c467125 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_consumer_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ Federation. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_consumer_sup). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_files.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_files.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_files.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_files.erl index ae78af3..5982e2e 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_files.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_files.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_files). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl similarity index 63% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl index d68e9ab..dd213d5 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_mgmt.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_mgmt). @@ -20,10 +20,10 @@ -export([dispatcher/0, web_ui/0]). -dispatcher() -> [{"/traces", rabbit_tracing_wm_traces, []}, - {"/traces/:vhost", rabbit_tracing_wm_traces, []}, - {"/traces/:vhost/:name", rabbit_tracing_wm_trace, []}, - {"/trace-files", rabbit_tracing_wm_files, []}, - {"/trace-files/:name", rabbit_tracing_wm_file, []}]. +dispatcher() -> [{["traces"], rabbit_tracing_wm_traces, []}, + {["traces", vhost], rabbit_tracing_wm_traces, []}, + {["traces", vhost, name], rabbit_tracing_wm_trace, []}, + {["trace-files"], rabbit_tracing_wm_files, []}, + {["trace-files", name], rabbit_tracing_wm_file, []}]. web_ui() -> [{javascript, <<"tracing.js">>}]. diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl index b3f1a9a..7cccd66 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_sup). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl similarity index 98% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl index 0dba25f..33914d1 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_traces.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_traces). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_util.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_util.erl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_util.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_util.erl diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl index ef2fa50..8966e8e 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_file.erl @@ -11,26 +11,24 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -module(rabbit_tracing_wm_file). --export([init/3]). --export([rest_init/2, resource_exists/2, serve/2, content_types_provided/2, +-export([init/1, resource_exists/2, serve/2, content_types_provided/2, is_authorized/2, allowed_methods/2, delete_resource/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"text/plain">>, serve}], ReqData, Context}. + {[{"text/plain", serve}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"DELETE">>], ReqData, Context}. + {['HEAD', 'GET', 'DELETE'], ReqData, Context}. resource_exists(ReqData, Context) -> Name = rabbit_mgmt_util:id(name, ReqData), diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl index 37ad49b..d4312c7 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_files.erl @@ -11,23 +11,22 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_wm_files). --export([init/3]). --export([rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. to_json(ReqData, Context) -> rabbit_mgmt_util:reply(rabbit_tracing_files:list(), ReqData, Context). diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl index 730bece..96456bb 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_trace.erl @@ -11,12 +11,11 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. -module(rabbit_tracing_wm_trace). --export([init/3]). --export([rest_init/2, resource_exists/2, to_json/2, +-export([init/1, resource_exists/2, to_json/2, content_types_provided/2, content_types_accepted/2, is_authorized/2, allowed_methods/2, accept_content/2, delete_resource/2]). @@ -26,21 +25,20 @@ -import(rabbit_misc, [pget/2, pget/3]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. - -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. content_types_accepted(ReqData, Context) -> - {[{<<"application/json">>, accept_content}], ReqData, Context}. + {[{"application/json", accept_content}], ReqData, Context}. allowed_methods(ReqData, Context) -> - {[<<"HEAD">>, <<"GET">>, <<"PUT">>, <<"DELETE">>], ReqData, Context}. + {['HEAD', 'GET', 'PUT', 'DELETE'], ReqData, Context}. resource_exists(ReqData, Context) -> {case trace(ReqData) of @@ -51,24 +49,22 @@ resource_exists(ReqData, Context) -> to_json(ReqData, Context) -> rabbit_mgmt_util:reply(trace(ReqData), ReqData, Context). -accept_content(ReqData0, Ctx) -> - case rabbit_mgmt_util:vhost(ReqData0) of +accept_content(RD, Ctx) -> + case rabbit_mgmt_util:vhost(RD) of not_found -> not_found; VHost -> - Name = rabbit_mgmt_util:id(name, ReqData0), + Name = rabbit_mgmt_util:id(name, RD), rabbit_mgmt_util:with_decode( - [format, pattern], ReqData0, Ctx, - fun([_, _], Trace, ReqData) -> + [format, pattern], RD, Ctx, + fun([_, _], Trace) -> Fs = [fun val_payload_bytes/3, fun val_format/3, fun val_create/3], case lists:foldl(fun (F, ok) -> F(VHost, Name, Trace); (_F, Err) -> Err end, ok, Fs) of - ok -> {true, ReqData, Ctx}; - Err -> rabbit_mgmt_util:bad_request(Err, - ReqData, - Ctx) + ok -> {true, RD, Ctx}; + Err -> rabbit_mgmt_util:bad_request(Err, RD, Ctx) end end) end. diff --git a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl similarity index 72% rename from rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl rename to deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl index 145b79b..959edc9 100644 --- a/rabbitmq-server/deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl +++ b/deps/rabbitmq_tracing/src/rabbit_tracing_wm_traces.erl @@ -11,23 +11,22 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_tracing_wm_traces). --export([init/3]). --export([rest_init/2, to_json/2, content_types_provided/2, is_authorized/2]). +-export([init/1, to_json/2, content_types_provided/2, is_authorized/2]). --include_lib("rabbitmq_management_agent/include/rabbit_mgmt_records.hrl"). +-include_lib("rabbitmq_management/include/rabbit_mgmt.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). %%-------------------------------------------------------------------- -init(_, _, _) -> {upgrade, protocol, cowboy_rest}. -rest_init(ReqData, _) -> {ok, ReqData, #context{}}. +init(_Config) -> {ok, #context{}}. content_types_provided(ReqData, Context) -> - {[{<<"application/json">>, to_json}], ReqData, Context}. + {[{"application/json", to_json}], ReqData, Context}. to_json(ReqData, Context) -> rabbit_mgmt_util:reply(rabbit_tracing_traces:list(), ReqData, Context). diff --git a/deps/rabbitmq_tracing/src/rabbitmq_tracing.app.src b/deps/rabbitmq_tracing/src/rabbitmq_tracing.app.src new file mode 100644 index 0000000..418239e --- /dev/null +++ b/deps/rabbitmq_tracing/src/rabbitmq_tracing.app.src @@ -0,0 +1,10 @@ +{application, rabbitmq_tracing, + [{description, "RabbitMQ message logging / tracing"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_tracing_app, []}}, + {env, [{directory, "/var/tmp/rabbitmq-tracing"}, + {username, <<"guest">>}, + {password, <<"guest">>}]}, + {applications, [kernel, stdlib, rabbit_common, rabbit, rabbitmq_management]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_trust_store/CODE_OF_CONDUCT.md b/deps/rabbitmq_trust_store/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_trust_store/CODE_OF_CONDUCT.md rename to deps/rabbitmq_trust_store/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/CONTRIBUTING.md b/deps/rabbitmq_trust_store/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/CONTRIBUTING.md rename to deps/rabbitmq_trust_store/CONTRIBUTING.md diff --git a/deps/rabbitmq_trust_store/Makefile b/deps/rabbitmq_trust_store/Makefile new file mode 100644 index 0000000..77a2ce7 --- /dev/null +++ b/deps/rabbitmq_trust_store/Makefile @@ -0,0 +1,17 @@ +PROJECT = rabbitmq_trust_store + +DEPS = rabbit_common rabbit +## We need the Cowboy's test utilities +TEST_DEPS = rabbitmq_ct_helpers amqp_client ct_helper +dep_ct_helper = git https://github.com/extend/ct_helper.git master + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/rabbitmq-server/deps/rabbitmq_trust_store/README.md b/deps/rabbitmq_trust_store/README.md similarity index 64% rename from rabbitmq-server/deps/rabbitmq_trust_store/README.md rename to deps/rabbitmq_trust_store/README.md index 874e67b..0934a54 100644 --- a/rabbitmq-server/deps/rabbitmq_trust_store/README.md +++ b/deps/rabbitmq_trust_store/README.md @@ -12,27 +12,16 @@ through various TLS socket options, namely the `ca_certs` and There is no convenient means with which to change it in realtime, that is, without making configuration changes to TLS listening sockets. -This plugin maintains a list of trusted .PEM formatted TLS (x509) certificates, -refreshing at configurable intervals, or when `rabbitmqctl +This plugin maintains a list of trusted .PEM formatted TLS (x509) certificates in a given +directory, refreshing at configurable intervals, or when `rabbitmqctl eval 'rabbit_trust_store:refresh().'` is invoked. Said certificates are then used to verify inbound TLS connections for the entire RabbitMQ node (all plugins and protocols). The list is node-local. -Certificates can be loaded from different sources (e.g. filesystem, HTTP server) -Sources are loaded using "providers" - erlang modules, implementing `rabbit_trust_store_certificate_provider` -behaviour. - -The default provider is `rabbit_trust_store_file_provider`, which will load certificates -from a configured local filesystem directory. - ## RabbitMQ Version Requirements This plugin requires RabbitMQ `3.6.1` or later. -## Erlang Version Requirements - -This plugin requires Erlang version 17.3 or later. - ## Installation and Binary Builds This plugin is now available from the [RabbitMQ community plugins page](http://www.rabbitmq.com/community-plugins.html). @@ -40,8 +29,6 @@ Please consult the docs on [how to install RabbitMQ plugins](http://www.rabbitmq ## Usage -### Filesystem provider - Configure the trust store with a directory of whitelisted certificates and a refresh interval: @@ -54,17 +41,16 @@ and a refresh interval: Setting `refresh_interval` to `0` seconds will disable automatic refresh. -Certificates are distinguished by their **filenames**, file modification time and -the hash of file contents. +Certificates are distinguished by their **filenames** and file modification time. -#### Installing a Certificate +### Installing a Certificate Write a `PEM` formatted certificate file to the configured directory to whitelist it. This contains all the necessary information to authorize a client which presents the very same certificate to the server. -#### Removing a Certificate +### Removing a Certificate Delete the certificate file from the configured directory to remove it from the whitelist. @@ -74,50 +60,6 @@ make it seem as if a removed certificate is still active. Disabling session cach in the broker by setting the `reuse_sessions` ssl option to `false` can be done if timely certificate removal is important. -### HTTP provider - -HTTP provider loads certificates via HTTP(S) from remote server. - -The server should have following API: - -- `GET ` - list certificates in JSON format: `{"certificates": [{"id": , "url": }, ...]}` -- `GET /` - download PEM encoded certificate. - -Where `` is a configured certificate path, `` - unique certificate identifier, -`` - relative certificate path to load it from server. - -Configuration of the HTTP provider: - -``` -{rabbitmq_trust_store, - [{providers, [rabbit_trust_store_http_provider]}, - {url, "http://example.cert.url/path"}, - {refresh_interval, {seconds, 30}} - ]}. -``` - -You can specify TLS options if you use HTTPS: - -``` -{rabbitmq_trust_store, - [{providers, [rabbit_trust_store_http_provider]}, - {url, "https://example.secure.cert.url/path"}, - {refresh_interval, {seconds, 30}}, - {ssl_options, [{certfile, "/client/cert.pem"}, - {keyfile, "/client/key.pem"}, - {cacertfile, "/ca/cert.pem"} - ]} - ]}. -``` - -HTTP provider uses `If-Modified-Since` during list request header to avoid updating -unchanged list of certificates. - -#### Example - -`examples/rabbitmq_trust_store_django` is an example Django application, which serves -certificates from a directory. - ### Listing certificates diff --git a/deps/rabbitmq_trust_store/erlang.mk b/deps/rabbitmq_trust_store/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_trust_store/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/deps/rabbitmq_trust_store/rabbitmq-components.mk b/deps/rabbitmq_trust_store/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_trust_store/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/deps/rabbitmq_trust_store/src/rabbit_trust_store.erl b/deps/rabbitmq_trust_store/src/rabbit_trust_store.erl new file mode 100644 index 0000000..d10c857 --- /dev/null +++ b/deps/rabbitmq_trust_store/src/rabbit_trust_store.erl @@ -0,0 +1,282 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +-module(rabbit_trust_store). +-behaviour(gen_server). + +-export([mode/0, refresh/0, list/0]). %% Console Interface. +-export([whitelisted/3, is_whitelisted/1]). %% Client-side Interface. +-export([start/1, start_link/1]). +-export([init/1, terminate/2, + handle_call/3, handle_cast/2, + handle_info/2, + code_change/3]). + +-include_lib("kernel/include/file.hrl"). +-include_lib("stdlib/include/ms_transform.hrl"). +-include_lib("public_key/include/public_key.hrl"). + +-type certificate() :: #'OTPCertificate'{}. +-type event() :: valid_peer + | valid + | {bad_cert, Other :: atom() + | unknown_ca + | selfsigned_peer} + | {extension, #'Extension'{}}. +-type state() :: confirmed | continue. +-type outcome() :: {valid, state()} + | {fail, Reason :: term()} + | {unknown, state()}. + +-record(entry, {filename :: string(), identifier :: tuple(), change_time :: integer()}). +-record(state, {directory_change_time :: integer(), whitelist_directory :: string(), refresh_interval :: integer()}). + + +%% OTP Supervision + +start(Settings) -> + gen_server:start(?MODULE, Settings, []). + +start_link(Settings) -> + gen_server:start_link({local, trust_store}, ?MODULE, Settings, []). + + +%% Console Interface + +-spec mode() -> 'automatic' | 'manual'. +mode() -> + gen_server:call(trust_store, mode). + +-spec refresh() -> integer(). +refresh() -> + gen_server:call(trust_store, refresh). + +-spec list() -> string(). +list() -> + gen_server:call(trust_store, list). + +%% Client (SSL Socket) Interface + +-spec whitelisted(certificate(), event(), state()) -> outcome(). +whitelisted(_, {bad_cert, unknown_ca}, confirmed) -> + {valid, confirmed}; +whitelisted(#'OTPCertificate'{}=C, {bad_cert, unknown_ca}, continue) -> + case is_whitelisted(C) of + true -> + {valid, confirmed}; + false -> + {fail, "CA not known AND certificate not whitelisted"} + end; +whitelisted(#'OTPCertificate'{}=C, {bad_cert, selfsigned_peer}, continue) -> + case is_whitelisted(C) of + true -> + {valid, confirmed}; + false -> + {fail, "certificate not whitelisted"} + end; +whitelisted(_, {bad_cert, _} = Reason, _) -> + {fail, Reason}; +whitelisted(_, valid, St) -> + {valid, St}; +whitelisted(#'OTPCertificate'{}=_, valid_peer, St) -> + {valid, St}; +whitelisted(_, {extension, _}, St) -> + {unknown, St}. + +-spec is_whitelisted(certificate()) -> boolean(). +is_whitelisted(#'OTPCertificate'{}=C) -> + #entry{identifier = Id} = extract_unique_attributes(C), + ets:member(table_name(), Id). + + +%% Generic Server Callbacks + +init(Settings) -> + erlang:process_flag(trap_exit, true), + ets:new(table_name(), table_options()), + Path = path(Settings), + Interval = refresh_interval(Settings), + Initial = modification_time(Path), + tabulate(Path), + if + Interval =:= 0 -> + ok; + Interval > 0 -> + erlang:send_after(Interval, erlang:self(), refresh) + end, + {ok, + #state{directory_change_time = Initial, + whitelist_directory = Path, + refresh_interval = Interval}}. + +handle_call(mode, _, St) -> + {reply, mode(St), St}; +handle_call(refresh, _, St) -> + {reply, refresh(St), St}; +handle_call(list, _, St) -> + {reply, list(St), St}; +handle_call(_, _, St) -> + {noreply, St}. + +handle_cast(_, St) -> + {noreply, St}. + +handle_info(refresh, #state{refresh_interval = Interval} = St) -> + New = refresh(St), + erlang:send_after(Interval, erlang:self(), refresh), + {noreply, St#state{directory_change_time = New}}; +handle_info(_, St) -> + {noreply, St}. + +terminate(shutdown, _St) -> + true = ets:delete(table_name()). + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%% Ancillary & Constants + +list(#state{whitelist_directory = Path}) -> + Formatted = + [format_cert(Path, F, S) || + #entry{filename = F, identifier = {_, S}} <- ets:tab2list(table_name())], + to_big_string(Formatted). + +mode(#state{refresh_interval = I}) -> + if + I =:= 0 -> 'manual'; + I > 0 -> 'automatic' + end. + +refresh(#state{whitelist_directory = Path, directory_change_time = Old}) -> + New = modification_time(Path), + case New > Old of + false -> + ok; + true -> + tabulate(Path) + end, + New. + +refresh_interval(Pairs) -> + {refresh_interval, S} = lists:keyfind(refresh_interval, 1, Pairs), + timer:seconds(S). + +path(Pairs) -> + {directory, Path} = lists:keyfind(directory, 1, Pairs), + Path. + +table_name() -> + trust_store_whitelist. + +table_options() -> + [protected, + named_table, + set, + {keypos, #entry.identifier}, + {heir, none}]. + +modification_time(Path) -> + {ok, Info} = file:read_file_info(Path, [{time, posix}]), + Info#file_info.mtime. + +already_whitelisted_filenames() -> + ets:select(table_name(), + ets:fun2ms(fun (#entry{filename = N, change_time = T}) -> {N, T} end)). + +one_whitelisted_filename({Name, Time}) -> + ets:fun2ms(fun (#entry{filename = N, change_time = T}) when N =:= Name, T =:= Time -> true end). + +build_entry(Path, {Name, Time}) -> + Absolute = filename:join(Path, Name), + Certificate = scan_then_parse(Absolute), + Unique = extract_unique_attributes(Certificate), + Unique#entry{filename = Name, change_time = Time}. + +try_build_entry(Path, {Name, Time}) -> + try build_entry(Path, {Name, Time}) of + Entry -> + rabbit_log:info( + "trust store: loading certificate '~s'", [Name]), + {ok, Entry} + catch + _:Err -> + rabbit_log:error( + "trust store: failed to load certificate '~s', error: ~p", + [Name, Err]), + {error, Err} + end. + +do_insertions(Before, After, Path) -> + Entries = [try_build_entry(Path, NameTime) || + NameTime <- (After -- Before)], + [insert(Entry) || {ok, Entry} <- Entries]. + +do_removals(Before, After) -> + [delete(NameTime) || NameTime <- (Before -- After)]. + +get_new(Path) -> + {ok, New} = file:list_dir(Path), + [{X, modification_time(filename:absname(X, Path))} || X <- New]. + +tabulate(Path) -> + Old = already_whitelisted_filenames(), + New = get_new(Path), + do_insertions(Old, New, Path), + do_removals(Old, New), + ok. + +delete({Name, Time}) -> + rabbit_log:info("removing certificate '~s'", [Name]), + ets:select_delete(table_name(), one_whitelisted_filename({Name, Time})). + +insert(Entry) -> + true = ets:insert(table_name(), Entry). + +scan_then_parse(Filename) when is_list(Filename) -> + {ok, Bin} = file:read_file(Filename), + [{'Certificate', Data, not_encrypted}] = public_key:pem_decode(Bin), + public_key:pkix_decode_cert(Data, otp). + +extract_unique_attributes(#'OTPCertificate'{}=C) -> + {Serial, Issuer} = case public_key:pkix_issuer_id(C, other) of + {error, _Reason} -> + {ok, Identifier} = public_key:pkix_issuer_id(C, self), + Identifier; + {ok, Identifier} -> + Identifier + end, + %% Why change the order of attributes? For the same reason we put + %% the *most significant figure* first (on the left hand side). + #entry{identifier = {Issuer, Serial}}. + +to_big_string(Formatted) -> + string:join([cert_to_string(X) || X <- Formatted], "~n~n"). + +cert_to_string({Name, Serial, Subject, Issuer, Validity}) -> + Text = + io_lib:format("Name: ~s~nSerial: ~p | 0x~.16.0B~nSubject: ~s~nIssuer: ~s~nValidity: ~p~n", + [ Name, Serial, Serial, Subject, Issuer, Validity]), + lists:flatten(Text). + +format_cert(Path, Name, Serial) -> + {ok, Bin} = file:read_file(filename:join(Path, Name)), + [{'Certificate', Data, not_encrypted}] = public_key:pem_decode(Bin), + Validity = rabbit_ssl:peer_cert_validity(Data), + Subject = rabbit_ssl:peer_cert_subject(Data), + Issuer = rabbit_ssl:peer_cert_issuer(Data), + {Name, Serial, Subject, Issuer, Validity}. + diff --git a/rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl b/deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl similarity index 57% rename from rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl rename to deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl index 521d623..1a2881f 100644 --- a/rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl +++ b/deps/rabbitmq_trust_store/src/rabbit_trust_store_app.erl @@ -10,7 +10,7 @@ %% %% The Original Code is RabbitMQ. %% -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_trust_store_app). @@ -18,6 +18,8 @@ -export([change_SSL_options/0]). -export([revert_SSL_options/0]). -export([start/2, stop/1]). +-define(DIRECTORY_OR_FILE_NAME_EXISTS, eexist). + -rabbit_boot_step({rabbit_trust_store, [ {description, "Change necessary SSL options."}, @@ -43,7 +45,12 @@ revert_SSL_options() -> ok = application:set_env(rabbit, ssl_options, Cfg). start(normal, _) -> - rabbit_trust_store_sup:start_link(). + + %% The below two are properties, that is, tuple of name/value. + Path = whitelist_path(), + Interval = refresh_interval_time(), + + rabbit_trust_store_sup:start_link([Path, Interval]). stop(_) -> ok. @@ -62,16 +69,9 @@ edit(Options) -> ok end, %% Only enter those options neccessary for this application. - %% - %% The `partial_chain` option was introduced in Erlng 17.3 (ssl - %% 5.3.6). So avoid its use with old versions. - {ok, SSLAppVsn} = application:get_key(ssl, vsn), - NewOptions = case rabbit_misc:version_compare(SSLAppVsn, "5.3.6", gte) of - true -> [{verify_fun, {delegate(), continue}}, - {partial_chain, fun partial_chain/1}]; - false -> [{verify_fun, {delegate(), continue}}] - end, - lists:keymerge(1, required_options(), NewOptions ++ Options). + lists:keymerge(1, required_options(), + [{verify_fun, {delegate(), continue}}, + {partial_chain, fun partial_chain/1} | Options]). delegate() -> fun rabbit_trust_store:whitelisted/3. @@ -91,3 +91,54 @@ partial_chain(Chain) -> required_options() -> [{verify, verify_peer}, {fail_if_no_peer_cert, true}]. + +whitelist_path() -> + Path = case application:get_env(rabbitmq_trust_store, directory) of + undefined -> + default_directory(); + {ok, V} when is_binary(V) -> + binary_to_list(V); + {ok, V} when is_list(V) -> + V + end, + ok = ensure_directory(Path), + {directory, Path}. + +refresh_interval_time() -> + case application:get_env(rabbitmq_trust_store, refresh_interval) of + undefined -> + {refresh_interval, default_refresh_interval()}; + {ok, S} when is_integer(S), S >= 0 -> + {refresh_interval, S}; + {ok, {seconds, S}} when is_integer(S), S >= 0 -> + {refresh_interval, S} + end. + +default_directory() -> + + %% Dismantle the directory tree: first the table & meta-data + %% directory, then the Mesia database directory, finally the node + %% directory where we will place the default whitelist in `Full`. + + Table = filename:split(rabbit_mnesia:dir()), + Mnesia = lists:droplast(Table), + Node = lists:droplast(Mnesia), + Full = Node ++ ["trust_store", "whitelist"], + filename:join(Full). + +default_refresh_interval() -> + {ok, I} = application:get_env(rabbitmq_trust_store, default_refresh_interval), + I. + +ensure_directory(Path) -> + ok = ensure_parent_directories(Path), + case file:make_dir(Path) of + {error, ?DIRECTORY_OR_FILE_NAME_EXISTS} -> + true = filelib:is_dir(Path), + ok; + ok -> + ok + end. + +ensure_parent_directories(Path) -> + filelib:ensure_dir(Path). diff --git a/rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl b/deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl similarity index 75% rename from rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl rename to deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl index 235d3fc..5e2562d 100644 --- a/rabbitmq-server/deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl +++ b/deps/rabbitmq_trust_store/src/rabbit_trust_store_sup.erl @@ -10,12 +10,12 @@ %% %% The Original Code is RabbitMQ. %% -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_trust_store_sup). -behaviour(supervisor). --export([start_link/0]). +-export([start_link/1]). -export([init/1]). -include_lib("rabbit_common/include/rabbit.hrl"). @@ -23,14 +23,15 @@ %% ... -start_link() -> - supervisor:start_link({local, ?MODULE}, ?MODULE, []). +start_link(Settings) -> + + supervisor:start_link({local, ?MODULE}, ?MODULE, Settings). %% ... -init([]) -> +init(Settings) -> {ok, {{one_for_one, 1, 5}, - [{trust_store, {rabbit_trust_store, start_link, []}, + [{trust_store, {rabbit_trust_store, start_link, [Settings]}, permanent, timer:seconds(5), worker, [rabbit_trust_store]}]}}. diff --git a/deps/rabbitmq_trust_store/src/rabbitmq_trust_store.app.src b/deps/rabbitmq_trust_store/src/rabbitmq_trust_store.app.src new file mode 100644 index 0000000..b2ae324 --- /dev/null +++ b/deps/rabbitmq_trust_store/src/rabbitmq_trust_store.app.src @@ -0,0 +1,16 @@ +{application, rabbitmq_trust_store, [ + {description, "Client certificate trust store. Provides a way to whitelist client x509 certificates."}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_trust_store_app, []}}, + {env, [ + {default_refresh_interval, 30} + ]}, + {applications, [ + kernel, + stdlib, + rabbit_common, + rabbit + ]} +]}. diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/CODE_OF_CONDUCT.md b/deps/rabbitmq_web_dispatch/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/CODE_OF_CONDUCT.md rename to deps/rabbitmq_web_dispatch/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_web_mqtt/CONTRIBUTING.md b/deps/rabbitmq_web_dispatch/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_mqtt/CONTRIBUTING.md rename to deps/rabbitmq_web_dispatch/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/LICENSE b/deps/rabbitmq_web_dispatch/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/LICENSE rename to deps/rabbitmq_web_dispatch/LICENSE diff --git a/deps/rabbitmq_web_dispatch/Makefile b/deps/rabbitmq_web_dispatch/Makefile new file mode 100644 index 0000000..986acac --- /dev/null +++ b/deps/rabbitmq_web_dispatch/Makefile @@ -0,0 +1,15 @@ +PROJECT = rabbitmq_web_dispatch + +DEPS = rabbit_common rabbit mochiweb webmachine +TEST_DEPS = rabbitmq_ct_helpers + +DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk + +# FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be +# reviewed and merged. + +ERLANG_MK_REPO = https://github.com/rabbitmq/erlang.mk.git +ERLANG_MK_COMMIT = rabbitmq-tmp + +include rabbitmq-components.mk +include erlang.mk diff --git a/deps/rabbitmq_web_dispatch/README.md b/deps/rabbitmq_web_dispatch/README.md new file mode 100644 index 0000000..425ef6d --- /dev/null +++ b/deps/rabbitmq_web_dispatch/README.md @@ -0,0 +1,25 @@ +rabbitmq-web-dispatch +--------------------- + +rabbitmq-web-dispatch is a thin veneer around mochiweb that provides the +ability for multiple applications to co-exist on mochiweb +listeners. Applications can register static docroots or dynamic +handlers to be executed, dispatched by URL path prefix. + +See http://www.rabbitmq.com/mochiweb.html for information on +configuring web plugins. + +The most general registration procedure is +`rabbit_web_dispatch:register_context_handler/5`. This takes a callback +procedure of the form + + loop(Request) -> + ... + +The module `rabbit_webmachine` provides a means of running more than +one webmachine in a VM, and understands rabbitmq-web-dispatch contexts. To +use it, supply a dispatch table term of the kind usually given to +webmachine in the file `priv/dispatch.conf`. + +`setup/{1,2}` in the same module allows some global configuration of +webmachine logging and error handling. diff --git a/deps/rabbitmq_web_dispatch/erlang.mk b/deps/rabbitmq_web_dispatch/erlang.mk new file mode 100644 index 0000000..6d2a31c --- /dev/null +++ b/deps/rabbitmq_web_dispatch/erlang.mk @@ -0,0 +1,6738 @@ +# Copyright (c) 2013-2015, Loïc Hoguin +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +.PHONY: all app apps deps search rel docs install-docs check tests clean distclean help erlang-mk + +ERLANG_MK_FILENAME := $(realpath $(lastword $(MAKEFILE_LIST))) + +ERLANG_MK_VERSION = 2.0.0-pre.2-144-g647ffd1 + +# Core configuration. + +PROJECT ?= $(notdir $(CURDIR)) +PROJECT := $(strip $(PROJECT)) + +PROJECT_VERSION ?= rolling +PROJECT_MOD ?= $(PROJECT)_app + +# Verbosity. + +V ?= 0 + +verbose_0 = @ +verbose_2 = set -x; +verbose = $(verbose_$(V)) + +gen_verbose_0 = @echo " GEN " $@; +gen_verbose_2 = set -x; +gen_verbose = $(gen_verbose_$(V)) + +# Temporary files directory. + +ERLANG_MK_TMP ?= $(CURDIR)/.erlang.mk +export ERLANG_MK_TMP + +# "erl" command. + +ERL = erl +A0 -noinput -boot start_clean + +# Platform detection. + +ifeq ($(PLATFORM),) +UNAME_S := $(shell uname -s) + +ifeq ($(UNAME_S),Linux) +PLATFORM = linux +else ifeq ($(UNAME_S),Darwin) +PLATFORM = darwin +else ifeq ($(UNAME_S),SunOS) +PLATFORM = solaris +else ifeq ($(UNAME_S),GNU) +PLATFORM = gnu +else ifeq ($(UNAME_S),FreeBSD) +PLATFORM = freebsd +else ifeq ($(UNAME_S),NetBSD) +PLATFORM = netbsd +else ifeq ($(UNAME_S),OpenBSD) +PLATFORM = openbsd +else ifeq ($(UNAME_S),DragonFly) +PLATFORM = dragonfly +else ifeq ($(shell uname -o),Msys) +PLATFORM = msys2 +else +$(error Unable to detect platform. Please open a ticket with the output of uname -a.) +endif + +export PLATFORM +endif + +# Core targets. + +all:: deps app rel + +# Noop to avoid a Make warning when there's nothing to do. +rel:: + $(verbose) : + +check:: tests + +clean:: clean-crashdump + +clean-crashdump: +ifneq ($(wildcard erl_crash.dump),) + $(gen_verbose) rm -f erl_crash.dump +endif + +distclean:: clean distclean-tmp + +distclean-tmp: + $(gen_verbose) rm -rf $(ERLANG_MK_TMP) + +help:: + $(verbose) printf "%s\n" \ + "erlang.mk (version $(ERLANG_MK_VERSION)) is distributed under the terms of the ISC License." \ + "Copyright (c) 2013-2015 Loïc Hoguin " \ + "" \ + "Usage: [V=1] $(MAKE) [target]..." \ + "" \ + "Core targets:" \ + " all Run deps, app and rel targets in that order" \ + " app Compile the project" \ + " deps Fetch dependencies (if needed) and compile them" \ + " fetch-deps Fetch dependencies recursively (if needed) without compiling them" \ + " list-deps List dependencies recursively on stdout" \ + " search q=... Search for a package in the built-in index" \ + " rel Build a release for this project, if applicable" \ + " docs Build the documentation for this project" \ + " install-docs Install the man pages for this project" \ + " check Compile and run all tests and analysis for this project" \ + " tests Run the tests for this project" \ + " clean Delete temporary and output files from most targets" \ + " distclean Delete all temporary and output files" \ + " help Display this help and exit" \ + " erlang-mk Update erlang.mk to the latest version" + +# Core functions. + +empty := +space := $(empty) $(empty) +tab := $(empty) $(empty) +comma := , + +define newline + + +endef + +define comma_list +$(subst $(space),$(comma),$(strip $(1))) +endef + +# Adding erlang.mk to make Erlang scripts who call init:get_plain_arguments() happy. +define erlang +$(ERL) $(2) -pz $(ERLANG_MK_TMP)/rebar/ebin -eval "$(subst $(newline),,$(subst ",\",$(1)))" -- erlang.mk +endef + +ifeq ($(PLATFORM),msys2) +core_native_path = $(subst \,\\\\,$(shell cygpath -w $1)) +else +core_native_path = $1 +endif + +ifeq ($(shell which wget 2>/dev/null | wc -l), 1) +define core_http_get + wget --no-check-certificate -O $(1) $(2)|| rm $(1) +endef +else +define core_http_get.erl + ssl:start(), + inets:start(), + case httpc:request(get, {"$(2)", []}, [{autoredirect, true}], []) of + {ok, {{_, 200, _}, _, Body}} -> + case file:write_file("$(1)", Body) of + ok -> ok; + {error, R1} -> halt(R1) + end; + {error, R2} -> + halt(R2) + end, + halt(0). +endef + +define core_http_get + $(call erlang,$(call core_http_get.erl,$(call core_native_path,$1),$2)) +endef +endif + +core_eq = $(and $(findstring $(1),$(2)),$(findstring $(2),$(1))) + +core_find = $(if $(wildcard $1),$(shell find $(1:%/=%) -type f -name $(subst *,\*,$2))) + +core_lc = $(subst A,a,$(subst B,b,$(subst C,c,$(subst D,d,$(subst E,e,$(subst F,f,$(subst G,g,$(subst H,h,$(subst I,i,$(subst J,j,$(subst K,k,$(subst L,l,$(subst M,m,$(subst N,n,$(subst O,o,$(subst P,p,$(subst Q,q,$(subst R,r,$(subst S,s,$(subst T,t,$(subst U,u,$(subst V,v,$(subst W,w,$(subst X,x,$(subst Y,y,$(subst Z,z,$(1))))))))))))))))))))))))))) + +core_ls = $(filter-out $(1),$(shell echo $(1))) + +# @todo Use a solution that does not require using perl. +core_relpath = $(shell perl -e 'use File::Spec; print File::Spec->abs2rel(@ARGV) . "\n"' $1 $2) + +# Automated update. + +ERLANG_MK_REPO ?= https://github.com/ninenines/erlang.mk +ERLANG_MK_COMMIT ?= +ERLANG_MK_BUILD_CONFIG ?= build.config +ERLANG_MK_BUILD_DIR ?= .erlang.mk.build + +erlang-mk: + git clone $(ERLANG_MK_REPO) $(ERLANG_MK_BUILD_DIR) +ifdef ERLANG_MK_COMMIT + cd $(ERLANG_MK_BUILD_DIR) && git checkout $(ERLANG_MK_COMMIT) +endif + if [ -f $(ERLANG_MK_BUILD_CONFIG) ]; then cp $(ERLANG_MK_BUILD_CONFIG) $(ERLANG_MK_BUILD_DIR)/build.config; fi + $(MAKE) -C $(ERLANG_MK_BUILD_DIR) + cp $(ERLANG_MK_BUILD_DIR)/erlang.mk ./erlang.mk + rm -rf $(ERLANG_MK_BUILD_DIR) + +# The erlang.mk package index is bundled in the default erlang.mk build. +# Search for the string "copyright" to skip to the rest of the code. + +PACKAGES += aberth +pkg_aberth_name = aberth +pkg_aberth_description = Generic BERT-RPC server in Erlang +pkg_aberth_homepage = https://github.com/a13x/aberth +pkg_aberth_fetch = git +pkg_aberth_repo = https://github.com/a13x/aberth +pkg_aberth_commit = master + +PACKAGES += active +pkg_active_name = active +pkg_active_description = Active development for Erlang: rebuild and reload source/binary files while the VM is running +pkg_active_homepage = https://github.com/proger/active +pkg_active_fetch = git +pkg_active_repo = https://github.com/proger/active +pkg_active_commit = master + +PACKAGES += actordb_core +pkg_actordb_core_name = actordb_core +pkg_actordb_core_description = ActorDB main source +pkg_actordb_core_homepage = http://www.actordb.com/ +pkg_actordb_core_fetch = git +pkg_actordb_core_repo = https://github.com/biokoda/actordb_core +pkg_actordb_core_commit = master + +PACKAGES += actordb_thrift +pkg_actordb_thrift_name = actordb_thrift +pkg_actordb_thrift_description = Thrift API for ActorDB +pkg_actordb_thrift_homepage = http://www.actordb.com/ +pkg_actordb_thrift_fetch = git +pkg_actordb_thrift_repo = https://github.com/biokoda/actordb_thrift +pkg_actordb_thrift_commit = master + +PACKAGES += aleppo +pkg_aleppo_name = aleppo +pkg_aleppo_description = Alternative Erlang Pre-Processor +pkg_aleppo_homepage = https://github.com/ErlyORM/aleppo +pkg_aleppo_fetch = git +pkg_aleppo_repo = https://github.com/ErlyORM/aleppo +pkg_aleppo_commit = master + +PACKAGES += alog +pkg_alog_name = alog +pkg_alog_description = Simply the best logging framework for Erlang +pkg_alog_homepage = https://github.com/siberian-fast-food/alogger +pkg_alog_fetch = git +pkg_alog_repo = https://github.com/siberian-fast-food/alogger +pkg_alog_commit = master + +PACKAGES += amqp_client +pkg_amqp_client_name = amqp_client +pkg_amqp_client_description = RabbitMQ Erlang AMQP client +pkg_amqp_client_homepage = https://www.rabbitmq.com/erlang-client-user-guide.html +pkg_amqp_client_fetch = git +pkg_amqp_client_repo = https://github.com/rabbitmq/rabbitmq-erlang-client.git +pkg_amqp_client_commit = master + +PACKAGES += annotations +pkg_annotations_name = annotations +pkg_annotations_description = Simple code instrumentation utilities +pkg_annotations_homepage = https://github.com/hyperthunk/annotations +pkg_annotations_fetch = git +pkg_annotations_repo = https://github.com/hyperthunk/annotations +pkg_annotations_commit = master + +PACKAGES += antidote +pkg_antidote_name = antidote +pkg_antidote_description = Large-scale computation without synchronisation +pkg_antidote_homepage = https://syncfree.lip6.fr/ +pkg_antidote_fetch = git +pkg_antidote_repo = https://github.com/SyncFree/antidote +pkg_antidote_commit = master + +PACKAGES += apns +pkg_apns_name = apns +pkg_apns_description = Apple Push Notification Server for Erlang +pkg_apns_homepage = http://inaka.github.com/apns4erl +pkg_apns_fetch = git +pkg_apns_repo = https://github.com/inaka/apns4erl +pkg_apns_commit = master + +PACKAGES += azdht +pkg_azdht_name = azdht +pkg_azdht_description = Azureus Distributed Hash Table (DHT) in Erlang +pkg_azdht_homepage = https://github.com/arcusfelis/azdht +pkg_azdht_fetch = git +pkg_azdht_repo = https://github.com/arcusfelis/azdht +pkg_azdht_commit = master + +PACKAGES += backoff +pkg_backoff_name = backoff +pkg_backoff_description = Simple exponential backoffs in Erlang +pkg_backoff_homepage = https://github.com/ferd/backoff +pkg_backoff_fetch = git +pkg_backoff_repo = https://github.com/ferd/backoff +pkg_backoff_commit = master + +PACKAGES += barrel_tcp +pkg_barrel_tcp_name = barrel_tcp +pkg_barrel_tcp_description = barrel is a generic TCP acceptor pool with low latency in Erlang. +pkg_barrel_tcp_homepage = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_fetch = git +pkg_barrel_tcp_repo = https://github.com/benoitc-attic/barrel_tcp +pkg_barrel_tcp_commit = master + +PACKAGES += basho_bench +pkg_basho_bench_name = basho_bench +pkg_basho_bench_description = A load-generation and testing tool for basically whatever you can write a returning Erlang function for. +pkg_basho_bench_homepage = https://github.com/basho/basho_bench +pkg_basho_bench_fetch = git +pkg_basho_bench_repo = https://github.com/basho/basho_bench +pkg_basho_bench_commit = master + +PACKAGES += bcrypt +pkg_bcrypt_name = bcrypt +pkg_bcrypt_description = Bcrypt Erlang / C library +pkg_bcrypt_homepage = https://github.com/riverrun/branglecrypt +pkg_bcrypt_fetch = git +pkg_bcrypt_repo = https://github.com/riverrun/branglecrypt +pkg_bcrypt_commit = master + +PACKAGES += beam +pkg_beam_name = beam +pkg_beam_description = BEAM emulator written in Erlang +pkg_beam_homepage = https://github.com/tonyrog/beam +pkg_beam_fetch = git +pkg_beam_repo = https://github.com/tonyrog/beam +pkg_beam_commit = master + +PACKAGES += beanstalk +pkg_beanstalk_name = beanstalk +pkg_beanstalk_description = An Erlang client for beanstalkd +pkg_beanstalk_homepage = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_fetch = git +pkg_beanstalk_repo = https://github.com/tim/erlang-beanstalk +pkg_beanstalk_commit = master + +PACKAGES += bear +pkg_bear_name = bear +pkg_bear_description = a set of statistics functions for erlang +pkg_bear_homepage = https://github.com/boundary/bear +pkg_bear_fetch = git +pkg_bear_repo = https://github.com/boundary/bear +pkg_bear_commit = master + +PACKAGES += bertconf +pkg_bertconf_name = bertconf +pkg_bertconf_description = Make ETS tables out of statc BERT files that are auto-reloaded +pkg_bertconf_homepage = https://github.com/ferd/bertconf +pkg_bertconf_fetch = git +pkg_bertconf_repo = https://github.com/ferd/bertconf +pkg_bertconf_commit = master + +PACKAGES += bifrost +pkg_bifrost_name = bifrost +pkg_bifrost_description = Erlang FTP Server Framework +pkg_bifrost_homepage = https://github.com/thorstadt/bifrost +pkg_bifrost_fetch = git +pkg_bifrost_repo = https://github.com/thorstadt/bifrost +pkg_bifrost_commit = master + +PACKAGES += binpp +pkg_binpp_name = binpp +pkg_binpp_description = Erlang Binary Pretty Printer +pkg_binpp_homepage = https://github.com/jtendo/binpp +pkg_binpp_fetch = git +pkg_binpp_repo = https://github.com/jtendo/binpp +pkg_binpp_commit = master + +PACKAGES += bisect +pkg_bisect_name = bisect +pkg_bisect_description = Ordered fixed-size binary dictionary in Erlang +pkg_bisect_homepage = https://github.com/knutin/bisect +pkg_bisect_fetch = git +pkg_bisect_repo = https://github.com/knutin/bisect +pkg_bisect_commit = master + +PACKAGES += bitcask +pkg_bitcask_name = bitcask +pkg_bitcask_description = because you need another a key/value storage engine +pkg_bitcask_homepage = https://github.com/basho/bitcask +pkg_bitcask_fetch = git +pkg_bitcask_repo = https://github.com/basho/bitcask +pkg_bitcask_commit = develop + +PACKAGES += bitstore +pkg_bitstore_name = bitstore +pkg_bitstore_description = A document based ontology development environment +pkg_bitstore_homepage = https://github.com/bdionne/bitstore +pkg_bitstore_fetch = git +pkg_bitstore_repo = https://github.com/bdionne/bitstore +pkg_bitstore_commit = master + +PACKAGES += bootstrap +pkg_bootstrap_name = bootstrap +pkg_bootstrap_description = A simple, yet powerful Erlang cluster bootstrapping application. +pkg_bootstrap_homepage = https://github.com/schlagert/bootstrap +pkg_bootstrap_fetch = git +pkg_bootstrap_repo = https://github.com/schlagert/bootstrap +pkg_bootstrap_commit = master + +PACKAGES += boss_db +pkg_boss_db_name = boss_db +pkg_boss_db_description = BossDB: a sharded, caching, pooling, evented ORM for Erlang +pkg_boss_db_homepage = https://github.com/ErlyORM/boss_db +pkg_boss_db_fetch = git +pkg_boss_db_repo = https://github.com/ErlyORM/boss_db +pkg_boss_db_commit = master + +PACKAGES += boss +pkg_boss_name = boss +pkg_boss_description = Erlang web MVC, now featuring Comet +pkg_boss_homepage = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_fetch = git +pkg_boss_repo = https://github.com/ChicagoBoss/ChicagoBoss +pkg_boss_commit = master + +PACKAGES += brod +pkg_brod_name = brod +pkg_brod_description = Kafka client in Erlang +pkg_brod_homepage = https://github.com/klarna/brod +pkg_brod_fetch = git +pkg_brod_repo = https://github.com/klarna/brod.git +pkg_brod_commit = master + +PACKAGES += bson +pkg_bson_name = bson +pkg_bson_description = BSON documents in Erlang, see bsonspec.org +pkg_bson_homepage = https://github.com/comtihon/bson-erlang +pkg_bson_fetch = git +pkg_bson_repo = https://github.com/comtihon/bson-erlang +pkg_bson_commit = master + +PACKAGES += bullet +pkg_bullet_name = bullet +pkg_bullet_description = Simple, reliable, efficient streaming for Cowboy. +pkg_bullet_homepage = http://ninenines.eu +pkg_bullet_fetch = git +pkg_bullet_repo = https://github.com/ninenines/bullet +pkg_bullet_commit = master + +PACKAGES += cache +pkg_cache_name = cache +pkg_cache_description = Erlang in-memory cache +pkg_cache_homepage = https://github.com/fogfish/cache +pkg_cache_fetch = git +pkg_cache_repo = https://github.com/fogfish/cache +pkg_cache_commit = master + +PACKAGES += cake +pkg_cake_name = cake +pkg_cake_description = Really simple terminal colorization +pkg_cake_homepage = https://github.com/darach/cake-erl +pkg_cake_fetch = git +pkg_cake_repo = https://github.com/darach/cake-erl +pkg_cake_commit = master + +PACKAGES += carotene +pkg_carotene_name = carotene +pkg_carotene_description = Real-time server +pkg_carotene_homepage = https://github.com/carotene/carotene +pkg_carotene_fetch = git +pkg_carotene_repo = https://github.com/carotene/carotene +pkg_carotene_commit = master + +PACKAGES += cberl +pkg_cberl_name = cberl +pkg_cberl_description = NIF based Erlang bindings for Couchbase +pkg_cberl_homepage = https://github.com/chitika/cberl +pkg_cberl_fetch = git +pkg_cberl_repo = https://github.com/chitika/cberl +pkg_cberl_commit = master + +PACKAGES += cecho +pkg_cecho_name = cecho +pkg_cecho_description = An ncurses library for Erlang +pkg_cecho_homepage = https://github.com/mazenharake/cecho +pkg_cecho_fetch = git +pkg_cecho_repo = https://github.com/mazenharake/cecho +pkg_cecho_commit = master + +PACKAGES += cferl +pkg_cferl_name = cferl +pkg_cferl_description = Rackspace / Open Stack Cloud Files Erlang Client +pkg_cferl_homepage = https://github.com/ddossot/cferl +pkg_cferl_fetch = git +pkg_cferl_repo = https://github.com/ddossot/cferl +pkg_cferl_commit = master + +PACKAGES += chaos_monkey +pkg_chaos_monkey_name = chaos_monkey +pkg_chaos_monkey_description = This is The CHAOS MONKEY. It will kill your processes. +pkg_chaos_monkey_homepage = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_fetch = git +pkg_chaos_monkey_repo = https://github.com/dLuna/chaos_monkey +pkg_chaos_monkey_commit = master + +PACKAGES += check_node +pkg_check_node_name = check_node +pkg_check_node_description = Nagios Scripts for monitoring Riak +pkg_check_node_homepage = https://github.com/basho-labs/riak_nagios +pkg_check_node_fetch = git +pkg_check_node_repo = https://github.com/basho-labs/riak_nagios +pkg_check_node_commit = master + +PACKAGES += chronos +pkg_chronos_name = chronos +pkg_chronos_description = Timer module for Erlang that makes it easy to abstact time out of the tests. +pkg_chronos_homepage = https://github.com/lehoff/chronos +pkg_chronos_fetch = git +pkg_chronos_repo = https://github.com/lehoff/chronos +pkg_chronos_commit = master + +PACKAGES += chumak +pkg_chumak_name = chumak +pkg_chumak_description = Pure Erlang implementation of ZeroMQ Message Transport Protocol. +pkg_chumak_homepage = http://choven.ca +pkg_chumak_fetch = git +pkg_chumak_repo = https://github.com/chovencorp/chumak +pkg_chumak_commit = master + +PACKAGES += cl +pkg_cl_name = cl +pkg_cl_description = OpenCL binding for Erlang +pkg_cl_homepage = https://github.com/tonyrog/cl +pkg_cl_fetch = git +pkg_cl_repo = https://github.com/tonyrog/cl +pkg_cl_commit = master + +PACKAGES += classifier +pkg_classifier_name = classifier +pkg_classifier_description = An Erlang Bayesian Filter and Text Classifier +pkg_classifier_homepage = https://github.com/inaka/classifier +pkg_classifier_fetch = git +pkg_classifier_repo = https://github.com/inaka/classifier +pkg_classifier_commit = master + +PACKAGES += clique +pkg_clique_name = clique +pkg_clique_description = CLI Framework for Erlang +pkg_clique_homepage = https://github.com/basho/clique +pkg_clique_fetch = git +pkg_clique_repo = https://github.com/basho/clique +pkg_clique_commit = develop + +PACKAGES += cloudi_core +pkg_cloudi_core_name = cloudi_core +pkg_cloudi_core_description = CloudI internal service runtime +pkg_cloudi_core_homepage = http://cloudi.org/ +pkg_cloudi_core_fetch = git +pkg_cloudi_core_repo = https://github.com/CloudI/cloudi_core +pkg_cloudi_core_commit = master + +PACKAGES += cloudi_service_api_requests +pkg_cloudi_service_api_requests_name = cloudi_service_api_requests +pkg_cloudi_service_api_requests_description = CloudI Service API requests (JSON-RPC/Erlang-term support) +pkg_cloudi_service_api_requests_homepage = http://cloudi.org/ +pkg_cloudi_service_api_requests_fetch = git +pkg_cloudi_service_api_requests_repo = https://github.com/CloudI/cloudi_service_api_requests +pkg_cloudi_service_api_requests_commit = master + +PACKAGES += cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_name = cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_description = Cassandra CQL CloudI Service +pkg_cloudi_service_db_cassandra_cql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_cql_fetch = git +pkg_cloudi_service_db_cassandra_cql_repo = https://github.com/CloudI/cloudi_service_db_cassandra_cql +pkg_cloudi_service_db_cassandra_cql_commit = master + +PACKAGES += cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_name = cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_description = Cassandra CloudI Service +pkg_cloudi_service_db_cassandra_homepage = http://cloudi.org/ +pkg_cloudi_service_db_cassandra_fetch = git +pkg_cloudi_service_db_cassandra_repo = https://github.com/CloudI/cloudi_service_db_cassandra +pkg_cloudi_service_db_cassandra_commit = master + +PACKAGES += cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_name = cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_description = CouchDB CloudI Service +pkg_cloudi_service_db_couchdb_homepage = http://cloudi.org/ +pkg_cloudi_service_db_couchdb_fetch = git +pkg_cloudi_service_db_couchdb_repo = https://github.com/CloudI/cloudi_service_db_couchdb +pkg_cloudi_service_db_couchdb_commit = master + +PACKAGES += cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_name = cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_description = elasticsearch CloudI Service +pkg_cloudi_service_db_elasticsearch_homepage = http://cloudi.org/ +pkg_cloudi_service_db_elasticsearch_fetch = git +pkg_cloudi_service_db_elasticsearch_repo = https://github.com/CloudI/cloudi_service_db_elasticsearch +pkg_cloudi_service_db_elasticsearch_commit = master + +PACKAGES += cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_name = cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_description = memcached CloudI Service +pkg_cloudi_service_db_memcached_homepage = http://cloudi.org/ +pkg_cloudi_service_db_memcached_fetch = git +pkg_cloudi_service_db_memcached_repo = https://github.com/CloudI/cloudi_service_db_memcached +pkg_cloudi_service_db_memcached_commit = master + +PACKAGES += cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_name = cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_description = MySQL CloudI Service +pkg_cloudi_service_db_mysql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_mysql_fetch = git +pkg_cloudi_service_db_mysql_repo = https://github.com/CloudI/cloudi_service_db_mysql +pkg_cloudi_service_db_mysql_commit = master + +PACKAGES += cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_name = cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_description = PostgreSQL CloudI Service +pkg_cloudi_service_db_pgsql_homepage = http://cloudi.org/ +pkg_cloudi_service_db_pgsql_fetch = git +pkg_cloudi_service_db_pgsql_repo = https://github.com/CloudI/cloudi_service_db_pgsql +pkg_cloudi_service_db_pgsql_commit = master + +PACKAGES += cloudi_service_db_riak +pkg_cloudi_service_db_riak_name = cloudi_service_db_riak +pkg_cloudi_service_db_riak_description = Riak CloudI Service +pkg_cloudi_service_db_riak_homepage = http://cloudi.org/ +pkg_cloudi_service_db_riak_fetch = git +pkg_cloudi_service_db_riak_repo = https://github.com/CloudI/cloudi_service_db_riak +pkg_cloudi_service_db_riak_commit = master + +PACKAGES += cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_name = cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_description = Tokyo Tyrant CloudI Service +pkg_cloudi_service_db_tokyotyrant_homepage = http://cloudi.org/ +pkg_cloudi_service_db_tokyotyrant_fetch = git +pkg_cloudi_service_db_tokyotyrant_repo = https://github.com/CloudI/cloudi_service_db_tokyotyrant +pkg_cloudi_service_db_tokyotyrant_commit = master + +PACKAGES += cloudi_service_db +pkg_cloudi_service_db_name = cloudi_service_db +pkg_cloudi_service_db_description = CloudI Database (in-memory/testing/generic) +pkg_cloudi_service_db_homepage = http://cloudi.org/ +pkg_cloudi_service_db_fetch = git +pkg_cloudi_service_db_repo = https://github.com/CloudI/cloudi_service_db +pkg_cloudi_service_db_commit = master + +PACKAGES += cloudi_service_filesystem +pkg_cloudi_service_filesystem_name = cloudi_service_filesystem +pkg_cloudi_service_filesystem_description = Filesystem CloudI Service +pkg_cloudi_service_filesystem_homepage = http://cloudi.org/ +pkg_cloudi_service_filesystem_fetch = git +pkg_cloudi_service_filesystem_repo = https://github.com/CloudI/cloudi_service_filesystem +pkg_cloudi_service_filesystem_commit = master + +PACKAGES += cloudi_service_http_client +pkg_cloudi_service_http_client_name = cloudi_service_http_client +pkg_cloudi_service_http_client_description = HTTP client CloudI Service +pkg_cloudi_service_http_client_homepage = http://cloudi.org/ +pkg_cloudi_service_http_client_fetch = git +pkg_cloudi_service_http_client_repo = https://github.com/CloudI/cloudi_service_http_client +pkg_cloudi_service_http_client_commit = master + +PACKAGES += cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_name = cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_description = cowboy HTTP/HTTPS CloudI Service +pkg_cloudi_service_http_cowboy_homepage = http://cloudi.org/ +pkg_cloudi_service_http_cowboy_fetch = git +pkg_cloudi_service_http_cowboy_repo = https://github.com/CloudI/cloudi_service_http_cowboy +pkg_cloudi_service_http_cowboy_commit = master + +PACKAGES += cloudi_service_http_elli +pkg_cloudi_service_http_elli_name = cloudi_service_http_elli +pkg_cloudi_service_http_elli_description = elli HTTP CloudI Service +pkg_cloudi_service_http_elli_homepage = http://cloudi.org/ +pkg_cloudi_service_http_elli_fetch = git +pkg_cloudi_service_http_elli_repo = https://github.com/CloudI/cloudi_service_http_elli +pkg_cloudi_service_http_elli_commit = master + +PACKAGES += cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_name = cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_description = Map/Reduce CloudI Service +pkg_cloudi_service_map_reduce_homepage = http://cloudi.org/ +pkg_cloudi_service_map_reduce_fetch = git +pkg_cloudi_service_map_reduce_repo = https://github.com/CloudI/cloudi_service_map_reduce +pkg_cloudi_service_map_reduce_commit = master + +PACKAGES += cloudi_service_oauth1 +pkg_cloudi_service_oauth1_name = cloudi_service_oauth1 +pkg_cloudi_service_oauth1_description = OAuth v1.0 CloudI Service +pkg_cloudi_service_oauth1_homepage = http://cloudi.org/ +pkg_cloudi_service_oauth1_fetch = git +pkg_cloudi_service_oauth1_repo = https://github.com/CloudI/cloudi_service_oauth1 +pkg_cloudi_service_oauth1_commit = master + +PACKAGES += cloudi_service_queue +pkg_cloudi_service_queue_name = cloudi_service_queue +pkg_cloudi_service_queue_description = Persistent Queue Service +pkg_cloudi_service_queue_homepage = http://cloudi.org/ +pkg_cloudi_service_queue_fetch = git +pkg_cloudi_service_queue_repo = https://github.com/CloudI/cloudi_service_queue +pkg_cloudi_service_queue_commit = master + +PACKAGES += cloudi_service_quorum +pkg_cloudi_service_quorum_name = cloudi_service_quorum +pkg_cloudi_service_quorum_description = CloudI Quorum Service +pkg_cloudi_service_quorum_homepage = http://cloudi.org/ +pkg_cloudi_service_quorum_fetch = git +pkg_cloudi_service_quorum_repo = https://github.com/CloudI/cloudi_service_quorum +pkg_cloudi_service_quorum_commit = master + +PACKAGES += cloudi_service_router +pkg_cloudi_service_router_name = cloudi_service_router +pkg_cloudi_service_router_description = CloudI Router Service +pkg_cloudi_service_router_homepage = http://cloudi.org/ +pkg_cloudi_service_router_fetch = git +pkg_cloudi_service_router_repo = https://github.com/CloudI/cloudi_service_router +pkg_cloudi_service_router_commit = master + +PACKAGES += cloudi_service_tcp +pkg_cloudi_service_tcp_name = cloudi_service_tcp +pkg_cloudi_service_tcp_description = TCP CloudI Service +pkg_cloudi_service_tcp_homepage = http://cloudi.org/ +pkg_cloudi_service_tcp_fetch = git +pkg_cloudi_service_tcp_repo = https://github.com/CloudI/cloudi_service_tcp +pkg_cloudi_service_tcp_commit = master + +PACKAGES += cloudi_service_timers +pkg_cloudi_service_timers_name = cloudi_service_timers +pkg_cloudi_service_timers_description = Timers CloudI Service +pkg_cloudi_service_timers_homepage = http://cloudi.org/ +pkg_cloudi_service_timers_fetch = git +pkg_cloudi_service_timers_repo = https://github.com/CloudI/cloudi_service_timers +pkg_cloudi_service_timers_commit = master + +PACKAGES += cloudi_service_udp +pkg_cloudi_service_udp_name = cloudi_service_udp +pkg_cloudi_service_udp_description = UDP CloudI Service +pkg_cloudi_service_udp_homepage = http://cloudi.org/ +pkg_cloudi_service_udp_fetch = git +pkg_cloudi_service_udp_repo = https://github.com/CloudI/cloudi_service_udp +pkg_cloudi_service_udp_commit = master + +PACKAGES += cloudi_service_validate +pkg_cloudi_service_validate_name = cloudi_service_validate +pkg_cloudi_service_validate_description = CloudI Validate Service +pkg_cloudi_service_validate_homepage = http://cloudi.org/ +pkg_cloudi_service_validate_fetch = git +pkg_cloudi_service_validate_repo = https://github.com/CloudI/cloudi_service_validate +pkg_cloudi_service_validate_commit = master + +PACKAGES += cloudi_service_zeromq +pkg_cloudi_service_zeromq_name = cloudi_service_zeromq +pkg_cloudi_service_zeromq_description = ZeroMQ CloudI Service +pkg_cloudi_service_zeromq_homepage = http://cloudi.org/ +pkg_cloudi_service_zeromq_fetch = git +pkg_cloudi_service_zeromq_repo = https://github.com/CloudI/cloudi_service_zeromq +pkg_cloudi_service_zeromq_commit = master + +PACKAGES += cluster_info +pkg_cluster_info_name = cluster_info +pkg_cluster_info_description = Fork of Hibari's nifty cluster_info OTP app +pkg_cluster_info_homepage = https://github.com/basho/cluster_info +pkg_cluster_info_fetch = git +pkg_cluster_info_repo = https://github.com/basho/cluster_info +pkg_cluster_info_commit = master + +PACKAGES += color +pkg_color_name = color +pkg_color_description = ANSI colors for your Erlang +pkg_color_homepage = https://github.com/julianduque/erlang-color +pkg_color_fetch = git +pkg_color_repo = https://github.com/julianduque/erlang-color +pkg_color_commit = master + +PACKAGES += confetti +pkg_confetti_name = confetti +pkg_confetti_description = Erlang configuration provider / application:get_env/2 on steroids +pkg_confetti_homepage = https://github.com/jtendo/confetti +pkg_confetti_fetch = git +pkg_confetti_repo = https://github.com/jtendo/confetti +pkg_confetti_commit = master + +PACKAGES += couchbeam +pkg_couchbeam_name = couchbeam +pkg_couchbeam_description = Apache CouchDB client in Erlang +pkg_couchbeam_homepage = https://github.com/benoitc/couchbeam +pkg_couchbeam_fetch = git +pkg_couchbeam_repo = https://github.com/benoitc/couchbeam +pkg_couchbeam_commit = master + +PACKAGES += covertool +pkg_covertool_name = covertool +pkg_covertool_description = Tool to convert Erlang cover data files into Cobertura XML reports +pkg_covertool_homepage = https://github.com/idubrov/covertool +pkg_covertool_fetch = git +pkg_covertool_repo = https://github.com/idubrov/covertool +pkg_covertool_commit = master + +PACKAGES += cowboy +pkg_cowboy_name = cowboy +pkg_cowboy_description = Small, fast and modular HTTP server. +pkg_cowboy_homepage = http://ninenines.eu +pkg_cowboy_fetch = git +pkg_cowboy_repo = https://github.com/ninenines/cowboy +pkg_cowboy_commit = 1.0.4 + +PACKAGES += cowdb +pkg_cowdb_name = cowdb +pkg_cowdb_description = Pure Key/Value database library for Erlang Applications +pkg_cowdb_homepage = https://github.com/refuge/cowdb +pkg_cowdb_fetch = git +pkg_cowdb_repo = https://github.com/refuge/cowdb +pkg_cowdb_commit = master + +PACKAGES += cowlib +pkg_cowlib_name = cowlib +pkg_cowlib_description = Support library for manipulating Web protocols. +pkg_cowlib_homepage = http://ninenines.eu +pkg_cowlib_fetch = git +pkg_cowlib_repo = https://github.com/ninenines/cowlib +pkg_cowlib_commit = 1.0.2 + +PACKAGES += cpg +pkg_cpg_name = cpg +pkg_cpg_description = CloudI Process Groups +pkg_cpg_homepage = https://github.com/okeuday/cpg +pkg_cpg_fetch = git +pkg_cpg_repo = https://github.com/okeuday/cpg +pkg_cpg_commit = master + +PACKAGES += cqerl +pkg_cqerl_name = cqerl +pkg_cqerl_description = Native Erlang CQL client for Cassandra +pkg_cqerl_homepage = https://matehat.github.io/cqerl/ +pkg_cqerl_fetch = git +pkg_cqerl_repo = https://github.com/matehat/cqerl +pkg_cqerl_commit = master + +PACKAGES += cr +pkg_cr_name = cr +pkg_cr_description = Chain Replication +pkg_cr_homepage = https://synrc.com/apps/cr/doc/cr.htm +pkg_cr_fetch = git +pkg_cr_repo = https://github.com/spawnproc/cr +pkg_cr_commit = master + +PACKAGES += cuttlefish +pkg_cuttlefish_name = cuttlefish +pkg_cuttlefish_description = never lose your childlike sense of wonder baby cuttlefish, promise me? +pkg_cuttlefish_homepage = https://github.com/basho/cuttlefish +pkg_cuttlefish_fetch = git +pkg_cuttlefish_repo = https://github.com/basho/cuttlefish +pkg_cuttlefish_commit = master + +PACKAGES += damocles +pkg_damocles_name = damocles +pkg_damocles_description = Erlang library for generating adversarial network conditions for QAing distributed applications/systems on a single Linux box. +pkg_damocles_homepage = https://github.com/lostcolony/damocles +pkg_damocles_fetch = git +pkg_damocles_repo = https://github.com/lostcolony/damocles +pkg_damocles_commit = master + +PACKAGES += debbie +pkg_debbie_name = debbie +pkg_debbie_description = .DEB Built In Erlang +pkg_debbie_homepage = https://github.com/crownedgrouse/debbie +pkg_debbie_fetch = git +pkg_debbie_repo = https://github.com/crownedgrouse/debbie +pkg_debbie_commit = master + +PACKAGES += decimal +pkg_decimal_name = decimal +pkg_decimal_description = An Erlang decimal arithmetic library +pkg_decimal_homepage = https://github.com/tim/erlang-decimal +pkg_decimal_fetch = git +pkg_decimal_repo = https://github.com/tim/erlang-decimal +pkg_decimal_commit = master + +PACKAGES += detergent +pkg_detergent_name = detergent +pkg_detergent_description = An emulsifying Erlang SOAP library +pkg_detergent_homepage = https://github.com/devinus/detergent +pkg_detergent_fetch = git +pkg_detergent_repo = https://github.com/devinus/detergent +pkg_detergent_commit = master + +PACKAGES += detest +pkg_detest_name = detest +pkg_detest_description = Tool for running tests on a cluster of erlang nodes +pkg_detest_homepage = https://github.com/biokoda/detest +pkg_detest_fetch = git +pkg_detest_repo = https://github.com/biokoda/detest +pkg_detest_commit = master + +PACKAGES += dh_date +pkg_dh_date_name = dh_date +pkg_dh_date_description = Date formatting / parsing library for erlang +pkg_dh_date_homepage = https://github.com/daleharvey/dh_date +pkg_dh_date_fetch = git +pkg_dh_date_repo = https://github.com/daleharvey/dh_date +pkg_dh_date_commit = master + +PACKAGES += dirbusterl +pkg_dirbusterl_name = dirbusterl +pkg_dirbusterl_description = DirBuster successor in Erlang +pkg_dirbusterl_homepage = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_fetch = git +pkg_dirbusterl_repo = https://github.com/silentsignal/DirBustErl +pkg_dirbusterl_commit = master + +PACKAGES += dispcount +pkg_dispcount_name = dispcount +pkg_dispcount_description = Erlang task dispatcher based on ETS counters. +pkg_dispcount_homepage = https://github.com/ferd/dispcount +pkg_dispcount_fetch = git +pkg_dispcount_repo = https://github.com/ferd/dispcount +pkg_dispcount_commit = master + +PACKAGES += dlhttpc +pkg_dlhttpc_name = dlhttpc +pkg_dlhttpc_description = dispcount-based lhttpc fork for massive amounts of requests to limited endpoints +pkg_dlhttpc_homepage = https://github.com/ferd/dlhttpc +pkg_dlhttpc_fetch = git +pkg_dlhttpc_repo = https://github.com/ferd/dlhttpc +pkg_dlhttpc_commit = master + +PACKAGES += dns +pkg_dns_name = dns +pkg_dns_description = Erlang DNS library +pkg_dns_homepage = https://github.com/aetrion/dns_erlang +pkg_dns_fetch = git +pkg_dns_repo = https://github.com/aetrion/dns_erlang +pkg_dns_commit = master + +PACKAGES += dnssd +pkg_dnssd_name = dnssd +pkg_dnssd_description = Erlang interface to Apple's Bonjour D NS Service Discovery implementation +pkg_dnssd_homepage = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_fetch = git +pkg_dnssd_repo = https://github.com/benoitc/dnssd_erlang +pkg_dnssd_commit = master + +PACKAGES += dtl +pkg_dtl_name = dtl +pkg_dtl_description = Django Template Language: A full-featured port of the Django template engine to Erlang. +pkg_dtl_homepage = https://github.com/oinksoft/dtl +pkg_dtl_fetch = git +pkg_dtl_repo = https://github.com/oinksoft/dtl +pkg_dtl_commit = master + +PACKAGES += dynamic_compile +pkg_dynamic_compile_name = dynamic_compile +pkg_dynamic_compile_description = compile and load erlang modules from string input +pkg_dynamic_compile_homepage = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_fetch = git +pkg_dynamic_compile_repo = https://github.com/jkvor/dynamic_compile +pkg_dynamic_compile_commit = master + +PACKAGES += e2 +pkg_e2_name = e2 +pkg_e2_description = Library to simply writing correct OTP applications. +pkg_e2_homepage = http://e2project.org +pkg_e2_fetch = git +pkg_e2_repo = https://github.com/gar1t/e2 +pkg_e2_commit = master + +PACKAGES += eamf +pkg_eamf_name = eamf +pkg_eamf_description = eAMF provides Action Message Format (AMF) support for Erlang +pkg_eamf_homepage = https://github.com/mrinalwadhwa/eamf +pkg_eamf_fetch = git +pkg_eamf_repo = https://github.com/mrinalwadhwa/eamf +pkg_eamf_commit = master + +PACKAGES += eavro +pkg_eavro_name = eavro +pkg_eavro_description = Apache Avro encoder/decoder +pkg_eavro_homepage = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_fetch = git +pkg_eavro_repo = https://github.com/SIfoxDevTeam/eavro +pkg_eavro_commit = master + +PACKAGES += ecapnp +pkg_ecapnp_name = ecapnp +pkg_ecapnp_description = Cap'n Proto library for Erlang +pkg_ecapnp_homepage = https://github.com/kaos/ecapnp +pkg_ecapnp_fetch = git +pkg_ecapnp_repo = https://github.com/kaos/ecapnp +pkg_ecapnp_commit = master + +PACKAGES += econfig +pkg_econfig_name = econfig +pkg_econfig_description = simple Erlang config handler using INI files +pkg_econfig_homepage = https://github.com/benoitc/econfig +pkg_econfig_fetch = git +pkg_econfig_repo = https://github.com/benoitc/econfig +pkg_econfig_commit = master + +PACKAGES += edate +pkg_edate_name = edate +pkg_edate_description = date manipulation library for erlang +pkg_edate_homepage = https://github.com/dweldon/edate +pkg_edate_fetch = git +pkg_edate_repo = https://github.com/dweldon/edate +pkg_edate_commit = master + +PACKAGES += edgar +pkg_edgar_name = edgar +pkg_edgar_description = Erlang Does GNU AR +pkg_edgar_homepage = https://github.com/crownedgrouse/edgar +pkg_edgar_fetch = git +pkg_edgar_repo = https://github.com/crownedgrouse/edgar +pkg_edgar_commit = master + +PACKAGES += edis +pkg_edis_name = edis +pkg_edis_description = An Erlang implementation of Redis KV Store +pkg_edis_homepage = http://inaka.github.com/edis/ +pkg_edis_fetch = git +pkg_edis_repo = https://github.com/inaka/edis +pkg_edis_commit = master + +PACKAGES += edns +pkg_edns_name = edns +pkg_edns_description = Erlang/OTP DNS server +pkg_edns_homepage = https://github.com/hcvst/erlang-dns +pkg_edns_fetch = git +pkg_edns_repo = https://github.com/hcvst/erlang-dns +pkg_edns_commit = master + +PACKAGES += edown +pkg_edown_name = edown +pkg_edown_description = EDoc extension for generating Github-flavored Markdown +pkg_edown_homepage = https://github.com/uwiger/edown +pkg_edown_fetch = git +pkg_edown_repo = https://github.com/uwiger/edown +pkg_edown_commit = master + +PACKAGES += eep_app +pkg_eep_app_name = eep_app +pkg_eep_app_description = Embedded Event Processing +pkg_eep_app_homepage = https://github.com/darach/eep-erl +pkg_eep_app_fetch = git +pkg_eep_app_repo = https://github.com/darach/eep-erl +pkg_eep_app_commit = master + +PACKAGES += eep +pkg_eep_name = eep +pkg_eep_description = Erlang Easy Profiling (eep) application provides a way to analyze application performance and call hierarchy +pkg_eep_homepage = https://github.com/virtan/eep +pkg_eep_fetch = git +pkg_eep_repo = https://github.com/virtan/eep +pkg_eep_commit = master + +PACKAGES += efene +pkg_efene_name = efene +pkg_efene_description = Alternative syntax for the Erlang Programming Language focusing on simplicity, ease of use and programmer UX +pkg_efene_homepage = https://github.com/efene/efene +pkg_efene_fetch = git +pkg_efene_repo = https://github.com/efene/efene +pkg_efene_commit = master + +PACKAGES += egeoip +pkg_egeoip_name = egeoip +pkg_egeoip_description = Erlang IP Geolocation module, currently supporting the MaxMind GeoLite City Database. +pkg_egeoip_homepage = https://github.com/mochi/egeoip +pkg_egeoip_fetch = git +pkg_egeoip_repo = https://github.com/mochi/egeoip +pkg_egeoip_commit = master + +PACKAGES += ehsa +pkg_ehsa_name = ehsa +pkg_ehsa_description = Erlang HTTP server basic and digest authentication modules +pkg_ehsa_homepage = https://bitbucket.org/a12n/ehsa +pkg_ehsa_fetch = hg +pkg_ehsa_repo = https://bitbucket.org/a12n/ehsa +pkg_ehsa_commit = default + +PACKAGES += ej +pkg_ej_name = ej +pkg_ej_description = Helper module for working with Erlang terms representing JSON +pkg_ej_homepage = https://github.com/seth/ej +pkg_ej_fetch = git +pkg_ej_repo = https://github.com/seth/ej +pkg_ej_commit = master + +PACKAGES += ejabberd +pkg_ejabberd_name = ejabberd +pkg_ejabberd_description = Robust, ubiquitous and massively scalable Jabber / XMPP Instant Messaging platform +pkg_ejabberd_homepage = https://github.com/processone/ejabberd +pkg_ejabberd_fetch = git +pkg_ejabberd_repo = https://github.com/processone/ejabberd +pkg_ejabberd_commit = master + +PACKAGES += ejwt +pkg_ejwt_name = ejwt +pkg_ejwt_description = erlang library for JSON Web Token +pkg_ejwt_homepage = https://github.com/artefactop/ejwt +pkg_ejwt_fetch = git +pkg_ejwt_repo = https://github.com/artefactop/ejwt +pkg_ejwt_commit = master + +PACKAGES += ekaf +pkg_ekaf_name = ekaf +pkg_ekaf_description = A minimal, high-performance Kafka client in Erlang. +pkg_ekaf_homepage = https://github.com/helpshift/ekaf +pkg_ekaf_fetch = git +pkg_ekaf_repo = https://github.com/helpshift/ekaf +pkg_ekaf_commit = master + +PACKAGES += elarm +pkg_elarm_name = elarm +pkg_elarm_description = Alarm Manager for Erlang. +pkg_elarm_homepage = https://github.com/esl/elarm +pkg_elarm_fetch = git +pkg_elarm_repo = https://github.com/esl/elarm +pkg_elarm_commit = master + +PACKAGES += eleveldb +pkg_eleveldb_name = eleveldb +pkg_eleveldb_description = Erlang LevelDB API +pkg_eleveldb_homepage = https://github.com/basho/eleveldb +pkg_eleveldb_fetch = git +pkg_eleveldb_repo = https://github.com/basho/eleveldb +pkg_eleveldb_commit = master + +PACKAGES += elli +pkg_elli_name = elli +pkg_elli_description = Simple, robust and performant Erlang web server +pkg_elli_homepage = https://github.com/knutin/elli +pkg_elli_fetch = git +pkg_elli_repo = https://github.com/knutin/elli +pkg_elli_commit = master + +PACKAGES += elvis +pkg_elvis_name = elvis +pkg_elvis_description = Erlang Style Reviewer +pkg_elvis_homepage = https://github.com/inaka/elvis +pkg_elvis_fetch = git +pkg_elvis_repo = https://github.com/inaka/elvis +pkg_elvis_commit = master + +PACKAGES += emagick +pkg_emagick_name = emagick +pkg_emagick_description = Wrapper for Graphics/ImageMagick command line tool. +pkg_emagick_homepage = https://github.com/kivra/emagick +pkg_emagick_fetch = git +pkg_emagick_repo = https://github.com/kivra/emagick +pkg_emagick_commit = master + +PACKAGES += emysql +pkg_emysql_name = emysql +pkg_emysql_description = Stable, pure Erlang MySQL driver. +pkg_emysql_homepage = https://github.com/Eonblast/Emysql +pkg_emysql_fetch = git +pkg_emysql_repo = https://github.com/Eonblast/Emysql +pkg_emysql_commit = master + +PACKAGES += enm +pkg_enm_name = enm +pkg_enm_description = Erlang driver for nanomsg +pkg_enm_homepage = https://github.com/basho/enm +pkg_enm_fetch = git +pkg_enm_repo = https://github.com/basho/enm +pkg_enm_commit = master + +PACKAGES += entop +pkg_entop_name = entop +pkg_entop_description = A top-like tool for monitoring an Erlang node +pkg_entop_homepage = https://github.com/mazenharake/entop +pkg_entop_fetch = git +pkg_entop_repo = https://github.com/mazenharake/entop +pkg_entop_commit = master + +PACKAGES += epcap +pkg_epcap_name = epcap +pkg_epcap_description = Erlang packet capture interface using pcap +pkg_epcap_homepage = https://github.com/msantos/epcap +pkg_epcap_fetch = git +pkg_epcap_repo = https://github.com/msantos/epcap +pkg_epcap_commit = master + +PACKAGES += eper +pkg_eper_name = eper +pkg_eper_description = Erlang performance and debugging tools. +pkg_eper_homepage = https://github.com/massemanet/eper +pkg_eper_fetch = git +pkg_eper_repo = https://github.com/massemanet/eper +pkg_eper_commit = master + +PACKAGES += epgsql +pkg_epgsql_name = epgsql +pkg_epgsql_description = Erlang PostgreSQL client library. +pkg_epgsql_homepage = https://github.com/epgsql/epgsql +pkg_epgsql_fetch = git +pkg_epgsql_repo = https://github.com/epgsql/epgsql +pkg_epgsql_commit = master + +PACKAGES += episcina +pkg_episcina_name = episcina +pkg_episcina_description = A simple non intrusive resource pool for connections +pkg_episcina_homepage = https://github.com/erlware/episcina +pkg_episcina_fetch = git +pkg_episcina_repo = https://github.com/erlware/episcina +pkg_episcina_commit = master + +PACKAGES += eplot +pkg_eplot_name = eplot +pkg_eplot_description = A plot engine written in erlang. +pkg_eplot_homepage = https://github.com/psyeugenic/eplot +pkg_eplot_fetch = git +pkg_eplot_repo = https://github.com/psyeugenic/eplot +pkg_eplot_commit = master + +PACKAGES += epocxy +pkg_epocxy_name = epocxy +pkg_epocxy_description = Erlang Patterns of Concurrency +pkg_epocxy_homepage = https://github.com/duomark/epocxy +pkg_epocxy_fetch = git +pkg_epocxy_repo = https://github.com/duomark/epocxy +pkg_epocxy_commit = master + +PACKAGES += epubnub +pkg_epubnub_name = epubnub +pkg_epubnub_description = Erlang PubNub API +pkg_epubnub_homepage = https://github.com/tsloughter/epubnub +pkg_epubnub_fetch = git +pkg_epubnub_repo = https://github.com/tsloughter/epubnub +pkg_epubnub_commit = master + +PACKAGES += eqm +pkg_eqm_name = eqm +pkg_eqm_description = Erlang pub sub with supply-demand channels +pkg_eqm_homepage = https://github.com/loucash/eqm +pkg_eqm_fetch = git +pkg_eqm_repo = https://github.com/loucash/eqm +pkg_eqm_commit = master + +PACKAGES += eredis_pool +pkg_eredis_pool_name = eredis_pool +pkg_eredis_pool_description = eredis_pool is Pool of Redis clients, using eredis and poolboy. +pkg_eredis_pool_homepage = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_fetch = git +pkg_eredis_pool_repo = https://github.com/hiroeorz/eredis_pool +pkg_eredis_pool_commit = master + +PACKAGES += eredis +pkg_eredis_name = eredis +pkg_eredis_description = Erlang Redis client +pkg_eredis_homepage = https://github.com/wooga/eredis +pkg_eredis_fetch = git +pkg_eredis_repo = https://github.com/wooga/eredis +pkg_eredis_commit = master + +PACKAGES += erl_streams +pkg_erl_streams_name = erl_streams +pkg_erl_streams_description = Streams in Erlang +pkg_erl_streams_homepage = https://github.com/epappas/erl_streams +pkg_erl_streams_fetch = git +pkg_erl_streams_repo = https://github.com/epappas/erl_streams +pkg_erl_streams_commit = master + +PACKAGES += erlang_cep +pkg_erlang_cep_name = erlang_cep +pkg_erlang_cep_description = A basic CEP package written in erlang +pkg_erlang_cep_homepage = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_fetch = git +pkg_erlang_cep_repo = https://github.com/danmacklin/erlang_cep +pkg_erlang_cep_commit = master + +PACKAGES += erlang_js +pkg_erlang_js_name = erlang_js +pkg_erlang_js_description = A linked-in driver for Erlang to Mozilla's Spidermonkey Javascript runtime. +pkg_erlang_js_homepage = https://github.com/basho/erlang_js +pkg_erlang_js_fetch = git +pkg_erlang_js_repo = https://github.com/basho/erlang_js +pkg_erlang_js_commit = master + +PACKAGES += erlang_localtime +pkg_erlang_localtime_name = erlang_localtime +pkg_erlang_localtime_description = Erlang library for conversion from one local time to another +pkg_erlang_localtime_homepage = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_fetch = git +pkg_erlang_localtime_repo = https://github.com/dmitryme/erlang_localtime +pkg_erlang_localtime_commit = master + +PACKAGES += erlang_smtp +pkg_erlang_smtp_name = erlang_smtp +pkg_erlang_smtp_description = Erlang SMTP and POP3 server code. +pkg_erlang_smtp_homepage = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_fetch = git +pkg_erlang_smtp_repo = https://github.com/tonyg/erlang-smtp +pkg_erlang_smtp_commit = master + +PACKAGES += erlang_term +pkg_erlang_term_name = erlang_term +pkg_erlang_term_description = Erlang Term Info +pkg_erlang_term_homepage = https://github.com/okeuday/erlang_term +pkg_erlang_term_fetch = git +pkg_erlang_term_repo = https://github.com/okeuday/erlang_term +pkg_erlang_term_commit = master + +PACKAGES += erlastic_search +pkg_erlastic_search_name = erlastic_search +pkg_erlastic_search_description = An Erlang app for communicating with Elastic Search's rest interface. +pkg_erlastic_search_homepage = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_fetch = git +pkg_erlastic_search_repo = https://github.com/tsloughter/erlastic_search +pkg_erlastic_search_commit = master + +PACKAGES += erlasticsearch +pkg_erlasticsearch_name = erlasticsearch +pkg_erlasticsearch_description = Erlang thrift interface to elastic_search +pkg_erlasticsearch_homepage = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_fetch = git +pkg_erlasticsearch_repo = https://github.com/dieswaytoofast/erlasticsearch +pkg_erlasticsearch_commit = master + +PACKAGES += erlbrake +pkg_erlbrake_name = erlbrake +pkg_erlbrake_description = Erlang Airbrake notification client +pkg_erlbrake_homepage = https://github.com/kenpratt/erlbrake +pkg_erlbrake_fetch = git +pkg_erlbrake_repo = https://github.com/kenpratt/erlbrake +pkg_erlbrake_commit = master + +PACKAGES += erlcloud +pkg_erlcloud_name = erlcloud +pkg_erlcloud_description = Cloud Computing library for erlang (Amazon EC2, S3, SQS, SimpleDB, Mechanical Turk, ELB) +pkg_erlcloud_homepage = https://github.com/gleber/erlcloud +pkg_erlcloud_fetch = git +pkg_erlcloud_repo = https://github.com/gleber/erlcloud +pkg_erlcloud_commit = master + +PACKAGES += erlcron +pkg_erlcron_name = erlcron +pkg_erlcron_description = Erlang cronish system +pkg_erlcron_homepage = https://github.com/erlware/erlcron +pkg_erlcron_fetch = git +pkg_erlcron_repo = https://github.com/erlware/erlcron +pkg_erlcron_commit = master + +PACKAGES += erldb +pkg_erldb_name = erldb +pkg_erldb_description = ORM (Object-relational mapping) application implemented in Erlang +pkg_erldb_homepage = http://erldb.org +pkg_erldb_fetch = git +pkg_erldb_repo = https://github.com/erldb/erldb +pkg_erldb_commit = master + +PACKAGES += erldis +pkg_erldis_name = erldis +pkg_erldis_description = redis erlang client library +pkg_erldis_homepage = https://github.com/cstar/erldis +pkg_erldis_fetch = git +pkg_erldis_repo = https://github.com/cstar/erldis +pkg_erldis_commit = master + +PACKAGES += erldns +pkg_erldns_name = erldns +pkg_erldns_description = DNS server, in erlang. +pkg_erldns_homepage = https://github.com/aetrion/erl-dns +pkg_erldns_fetch = git +pkg_erldns_repo = https://github.com/aetrion/erl-dns +pkg_erldns_commit = master + +PACKAGES += erldocker +pkg_erldocker_name = erldocker +pkg_erldocker_description = Docker Remote API client for Erlang +pkg_erldocker_homepage = https://github.com/proger/erldocker +pkg_erldocker_fetch = git +pkg_erldocker_repo = https://github.com/proger/erldocker +pkg_erldocker_commit = master + +PACKAGES += erlfsmon +pkg_erlfsmon_name = erlfsmon +pkg_erlfsmon_description = Erlang filesystem event watcher for Linux and OSX +pkg_erlfsmon_homepage = https://github.com/proger/erlfsmon +pkg_erlfsmon_fetch = git +pkg_erlfsmon_repo = https://github.com/proger/erlfsmon +pkg_erlfsmon_commit = master + +PACKAGES += erlgit +pkg_erlgit_name = erlgit +pkg_erlgit_description = Erlang convenience wrapper around git executable +pkg_erlgit_homepage = https://github.com/gleber/erlgit +pkg_erlgit_fetch = git +pkg_erlgit_repo = https://github.com/gleber/erlgit +pkg_erlgit_commit = master + +PACKAGES += erlguten +pkg_erlguten_name = erlguten +pkg_erlguten_description = ErlGuten is a system for high-quality typesetting, written purely in Erlang. +pkg_erlguten_homepage = https://github.com/richcarl/erlguten +pkg_erlguten_fetch = git +pkg_erlguten_repo = https://github.com/richcarl/erlguten +pkg_erlguten_commit = master + +PACKAGES += erlmc +pkg_erlmc_name = erlmc +pkg_erlmc_description = Erlang memcached binary protocol client +pkg_erlmc_homepage = https://github.com/jkvor/erlmc +pkg_erlmc_fetch = git +pkg_erlmc_repo = https://github.com/jkvor/erlmc +pkg_erlmc_commit = master + +PACKAGES += erlmongo +pkg_erlmongo_name = erlmongo +pkg_erlmongo_description = Record based Erlang driver for MongoDB with gridfs support +pkg_erlmongo_homepage = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_fetch = git +pkg_erlmongo_repo = https://github.com/SergejJurecko/erlmongo +pkg_erlmongo_commit = master + +PACKAGES += erlog +pkg_erlog_name = erlog +pkg_erlog_description = Prolog interpreter in and for Erlang +pkg_erlog_homepage = https://github.com/rvirding/erlog +pkg_erlog_fetch = git +pkg_erlog_repo = https://github.com/rvirding/erlog +pkg_erlog_commit = master + +PACKAGES += erlpass +pkg_erlpass_name = erlpass +pkg_erlpass_description = A library to handle password hashing and changing in a safe manner, independent from any kind of storage whatsoever. +pkg_erlpass_homepage = https://github.com/ferd/erlpass +pkg_erlpass_fetch = git +pkg_erlpass_repo = https://github.com/ferd/erlpass +pkg_erlpass_commit = master + +PACKAGES += erlport +pkg_erlport_name = erlport +pkg_erlport_description = ErlPort - connect Erlang to other languages +pkg_erlport_homepage = https://github.com/hdima/erlport +pkg_erlport_fetch = git +pkg_erlport_repo = https://github.com/hdima/erlport +pkg_erlport_commit = master + +PACKAGES += erlsh +pkg_erlsh_name = erlsh +pkg_erlsh_description = Erlang shell tools +pkg_erlsh_homepage = https://github.com/proger/erlsh +pkg_erlsh_fetch = git +pkg_erlsh_repo = https://github.com/proger/erlsh +pkg_erlsh_commit = master + +PACKAGES += erlsha2 +pkg_erlsha2_name = erlsha2 +pkg_erlsha2_description = SHA-224, SHA-256, SHA-384, SHA-512 implemented in Erlang NIFs. +pkg_erlsha2_homepage = https://github.com/vinoski/erlsha2 +pkg_erlsha2_fetch = git +pkg_erlsha2_repo = https://github.com/vinoski/erlsha2 +pkg_erlsha2_commit = master + +PACKAGES += erlsom +pkg_erlsom_name = erlsom +pkg_erlsom_description = XML parser for Erlang +pkg_erlsom_homepage = https://github.com/willemdj/erlsom +pkg_erlsom_fetch = git +pkg_erlsom_repo = https://github.com/willemdj/erlsom +pkg_erlsom_commit = master + +PACKAGES += erlubi +pkg_erlubi_name = erlubi +pkg_erlubi_description = Ubigraph Erlang Client (and Process Visualizer) +pkg_erlubi_homepage = https://github.com/krestenkrab/erlubi +pkg_erlubi_fetch = git +pkg_erlubi_repo = https://github.com/krestenkrab/erlubi +pkg_erlubi_commit = master + +PACKAGES += erlvolt +pkg_erlvolt_name = erlvolt +pkg_erlvolt_description = VoltDB Erlang Client Driver +pkg_erlvolt_homepage = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_fetch = git +pkg_erlvolt_repo = https://github.com/VoltDB/voltdb-client-erlang +pkg_erlvolt_commit = master + +PACKAGES += erlware_commons +pkg_erlware_commons_name = erlware_commons +pkg_erlware_commons_description = Erlware Commons is an Erlware project focused on all aspects of reusable Erlang components. +pkg_erlware_commons_homepage = https://github.com/erlware/erlware_commons +pkg_erlware_commons_fetch = git +pkg_erlware_commons_repo = https://github.com/erlware/erlware_commons +pkg_erlware_commons_commit = master + +PACKAGES += erlydtl +pkg_erlydtl_name = erlydtl +pkg_erlydtl_description = Django Template Language for Erlang. +pkg_erlydtl_homepage = https://github.com/erlydtl/erlydtl +pkg_erlydtl_fetch = git +pkg_erlydtl_repo = https://github.com/erlydtl/erlydtl +pkg_erlydtl_commit = master + +PACKAGES += errd +pkg_errd_name = errd +pkg_errd_description = Erlang RRDTool library +pkg_errd_homepage = https://github.com/archaelus/errd +pkg_errd_fetch = git +pkg_errd_repo = https://github.com/archaelus/errd +pkg_errd_commit = master + +PACKAGES += erserve +pkg_erserve_name = erserve +pkg_erserve_description = Erlang/Rserve communication interface +pkg_erserve_homepage = https://github.com/del/erserve +pkg_erserve_fetch = git +pkg_erserve_repo = https://github.com/del/erserve +pkg_erserve_commit = master + +PACKAGES += erwa +pkg_erwa_name = erwa +pkg_erwa_description = A WAMP router and client written in Erlang. +pkg_erwa_homepage = https://github.com/bwegh/erwa +pkg_erwa_fetch = git +pkg_erwa_repo = https://github.com/bwegh/erwa +pkg_erwa_commit = master + +PACKAGES += espec +pkg_espec_name = espec +pkg_espec_description = ESpec: Behaviour driven development framework for Erlang +pkg_espec_homepage = https://github.com/lucaspiller/espec +pkg_espec_fetch = git +pkg_espec_repo = https://github.com/lucaspiller/espec +pkg_espec_commit = master + +PACKAGES += estatsd +pkg_estatsd_name = estatsd +pkg_estatsd_description = Erlang stats aggregation app that periodically flushes data to graphite +pkg_estatsd_homepage = https://github.com/RJ/estatsd +pkg_estatsd_fetch = git +pkg_estatsd_repo = https://github.com/RJ/estatsd +pkg_estatsd_commit = master + +PACKAGES += etap +pkg_etap_name = etap +pkg_etap_description = etap is a simple erlang testing library that provides TAP compliant output. +pkg_etap_homepage = https://github.com/ngerakines/etap +pkg_etap_fetch = git +pkg_etap_repo = https://github.com/ngerakines/etap +pkg_etap_commit = master + +PACKAGES += etest_http +pkg_etest_http_name = etest_http +pkg_etest_http_description = etest Assertions around HTTP (client-side) +pkg_etest_http_homepage = https://github.com/wooga/etest_http +pkg_etest_http_fetch = git +pkg_etest_http_repo = https://github.com/wooga/etest_http +pkg_etest_http_commit = master + +PACKAGES += etest +pkg_etest_name = etest +pkg_etest_description = A lightweight, convention over configuration test framework for Erlang +pkg_etest_homepage = https://github.com/wooga/etest +pkg_etest_fetch = git +pkg_etest_repo = https://github.com/wooga/etest +pkg_etest_commit = master + +PACKAGES += etoml +pkg_etoml_name = etoml +pkg_etoml_description = TOML language erlang parser +pkg_etoml_homepage = https://github.com/kalta/etoml +pkg_etoml_fetch = git +pkg_etoml_repo = https://github.com/kalta/etoml +pkg_etoml_commit = master + +PACKAGES += eunit_formatters +pkg_eunit_formatters_name = eunit_formatters +pkg_eunit_formatters_description = Because eunit's output sucks. Let's make it better. +pkg_eunit_formatters_homepage = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_fetch = git +pkg_eunit_formatters_repo = https://github.com/seancribbs/eunit_formatters +pkg_eunit_formatters_commit = master + +PACKAGES += eunit +pkg_eunit_name = eunit +pkg_eunit_description = The EUnit lightweight unit testing framework for Erlang - this is the canonical development repository. +pkg_eunit_homepage = https://github.com/richcarl/eunit +pkg_eunit_fetch = git +pkg_eunit_repo = https://github.com/richcarl/eunit +pkg_eunit_commit = master + +PACKAGES += euthanasia +pkg_euthanasia_name = euthanasia +pkg_euthanasia_description = Merciful killer for your Erlang processes +pkg_euthanasia_homepage = https://github.com/doubleyou/euthanasia +pkg_euthanasia_fetch = git +pkg_euthanasia_repo = https://github.com/doubleyou/euthanasia +pkg_euthanasia_commit = master + +PACKAGES += evum +pkg_evum_name = evum +pkg_evum_description = Spawn Linux VMs as Erlang processes in the Erlang VM +pkg_evum_homepage = https://github.com/msantos/evum +pkg_evum_fetch = git +pkg_evum_repo = https://github.com/msantos/evum +pkg_evum_commit = master + +PACKAGES += exec +pkg_exec_name = exec +pkg_exec_description = Execute and control OS processes from Erlang/OTP. +pkg_exec_homepage = http://saleyn.github.com/erlexec +pkg_exec_fetch = git +pkg_exec_repo = https://github.com/saleyn/erlexec +pkg_exec_commit = master + +PACKAGES += exml +pkg_exml_name = exml +pkg_exml_description = XML parsing library in Erlang +pkg_exml_homepage = https://github.com/paulgray/exml +pkg_exml_fetch = git +pkg_exml_repo = https://github.com/paulgray/exml +pkg_exml_commit = master + +PACKAGES += exometer +pkg_exometer_name = exometer +pkg_exometer_description = Basic measurement objects and probe behavior +pkg_exometer_homepage = https://github.com/Feuerlabs/exometer +pkg_exometer_fetch = git +pkg_exometer_repo = https://github.com/Feuerlabs/exometer +pkg_exometer_commit = master + +PACKAGES += exs1024 +pkg_exs1024_name = exs1024 +pkg_exs1024_description = Xorshift1024star pseudo random number generator for Erlang. +pkg_exs1024_homepage = https://github.com/jj1bdx/exs1024 +pkg_exs1024_fetch = git +pkg_exs1024_repo = https://github.com/jj1bdx/exs1024 +pkg_exs1024_commit = master + +PACKAGES += exs64 +pkg_exs64_name = exs64 +pkg_exs64_description = Xorshift64star pseudo random number generator for Erlang. +pkg_exs64_homepage = https://github.com/jj1bdx/exs64 +pkg_exs64_fetch = git +pkg_exs64_repo = https://github.com/jj1bdx/exs64 +pkg_exs64_commit = master + +PACKAGES += exsplus116 +pkg_exsplus116_name = exsplus116 +pkg_exsplus116_description = Xorshift116plus for Erlang +pkg_exsplus116_homepage = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_fetch = git +pkg_exsplus116_repo = https://github.com/jj1bdx/exsplus116 +pkg_exsplus116_commit = master + +PACKAGES += exsplus128 +pkg_exsplus128_name = exsplus128 +pkg_exsplus128_description = Xorshift128plus pseudo random number generator for Erlang. +pkg_exsplus128_homepage = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_fetch = git +pkg_exsplus128_repo = https://github.com/jj1bdx/exsplus128 +pkg_exsplus128_commit = master + +PACKAGES += ezmq +pkg_ezmq_name = ezmq +pkg_ezmq_description = zMQ implemented in Erlang +pkg_ezmq_homepage = https://github.com/RoadRunnr/ezmq +pkg_ezmq_fetch = git +pkg_ezmq_repo = https://github.com/RoadRunnr/ezmq +pkg_ezmq_commit = master + +PACKAGES += ezmtp +pkg_ezmtp_name = ezmtp +pkg_ezmtp_description = ZMTP protocol in pure Erlang. +pkg_ezmtp_homepage = https://github.com/a13x/ezmtp +pkg_ezmtp_fetch = git +pkg_ezmtp_repo = https://github.com/a13x/ezmtp +pkg_ezmtp_commit = master + +PACKAGES += fast_disk_log +pkg_fast_disk_log_name = fast_disk_log +pkg_fast_disk_log_description = Pool-based asynchronous Erlang disk logger +pkg_fast_disk_log_homepage = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_fetch = git +pkg_fast_disk_log_repo = https://github.com/lpgauth/fast_disk_log +pkg_fast_disk_log_commit = master + +PACKAGES += feeder +pkg_feeder_name = feeder +pkg_feeder_description = Stream parse RSS and Atom formatted XML feeds. +pkg_feeder_homepage = https://github.com/michaelnisi/feeder +pkg_feeder_fetch = git +pkg_feeder_repo = https://github.com/michaelnisi/feeder +pkg_feeder_commit = master + +PACKAGES += find_crate +pkg_find_crate_name = find_crate +pkg_find_crate_description = Find Rust libs and exes in Erlang application priv directory +pkg_find_crate_homepage = https://github.com/goertzenator/find_crate +pkg_find_crate_fetch = git +pkg_find_crate_repo = https://github.com/goertzenator/find_crate +pkg_find_crate_commit = master + +PACKAGES += fix +pkg_fix_name = fix +pkg_fix_description = http://fixprotocol.org/ implementation. +pkg_fix_homepage = https://github.com/maxlapshin/fix +pkg_fix_fetch = git +pkg_fix_repo = https://github.com/maxlapshin/fix +pkg_fix_commit = master + +PACKAGES += flower +pkg_flower_name = flower +pkg_flower_description = FlowER - a Erlang OpenFlow development platform +pkg_flower_homepage = https://github.com/travelping/flower +pkg_flower_fetch = git +pkg_flower_repo = https://github.com/travelping/flower +pkg_flower_commit = master + +PACKAGES += fn +pkg_fn_name = fn +pkg_fn_description = Function utilities for Erlang +pkg_fn_homepage = https://github.com/reiddraper/fn +pkg_fn_fetch = git +pkg_fn_repo = https://github.com/reiddraper/fn +pkg_fn_commit = master + +PACKAGES += folsom_cowboy +pkg_folsom_cowboy_name = folsom_cowboy +pkg_folsom_cowboy_description = A Cowboy based Folsom HTTP Wrapper. +pkg_folsom_cowboy_homepage = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_fetch = git +pkg_folsom_cowboy_repo = https://github.com/boundary/folsom_cowboy +pkg_folsom_cowboy_commit = master + +PACKAGES += folsom +pkg_folsom_name = folsom +pkg_folsom_description = Expose Erlang Events and Metrics +pkg_folsom_homepage = https://github.com/boundary/folsom +pkg_folsom_fetch = git +pkg_folsom_repo = https://github.com/boundary/folsom +pkg_folsom_commit = master + +PACKAGES += folsomite +pkg_folsomite_name = folsomite +pkg_folsomite_description = blow up your graphite / riemann server with folsom metrics +pkg_folsomite_homepage = https://github.com/campanja/folsomite +pkg_folsomite_fetch = git +pkg_folsomite_repo = https://github.com/campanja/folsomite +pkg_folsomite_commit = master + +PACKAGES += fs +pkg_fs_name = fs +pkg_fs_description = Erlang FileSystem Listener +pkg_fs_homepage = https://github.com/synrc/fs +pkg_fs_fetch = git +pkg_fs_repo = https://github.com/synrc/fs +pkg_fs_commit = master + +PACKAGES += fuse +pkg_fuse_name = fuse +pkg_fuse_description = A Circuit Breaker for Erlang +pkg_fuse_homepage = https://github.com/jlouis/fuse +pkg_fuse_fetch = git +pkg_fuse_repo = https://github.com/jlouis/fuse +pkg_fuse_commit = master + +PACKAGES += gcm +pkg_gcm_name = gcm +pkg_gcm_description = An Erlang application for Google Cloud Messaging +pkg_gcm_homepage = https://github.com/pdincau/gcm-erlang +pkg_gcm_fetch = git +pkg_gcm_repo = https://github.com/pdincau/gcm-erlang +pkg_gcm_commit = master + +PACKAGES += gcprof +pkg_gcprof_name = gcprof +pkg_gcprof_description = Garbage Collection profiler for Erlang +pkg_gcprof_homepage = https://github.com/knutin/gcprof +pkg_gcprof_fetch = git +pkg_gcprof_repo = https://github.com/knutin/gcprof +pkg_gcprof_commit = master + +PACKAGES += geas +pkg_geas_name = geas +pkg_geas_description = Guess Erlang Application Scattering +pkg_geas_homepage = https://github.com/crownedgrouse/geas +pkg_geas_fetch = git +pkg_geas_repo = https://github.com/crownedgrouse/geas +pkg_geas_commit = master + +PACKAGES += geef +pkg_geef_name = geef +pkg_geef_description = Git NEEEEF (Erlang NIF) +pkg_geef_homepage = https://github.com/carlosmn/geef +pkg_geef_fetch = git +pkg_geef_repo = https://github.com/carlosmn/geef +pkg_geef_commit = master + +PACKAGES += gen_coap +pkg_gen_coap_name = gen_coap +pkg_gen_coap_description = Generic Erlang CoAP Client/Server +pkg_gen_coap_homepage = https://github.com/gotthardp/gen_coap +pkg_gen_coap_fetch = git +pkg_gen_coap_repo = https://github.com/gotthardp/gen_coap +pkg_gen_coap_commit = master + +PACKAGES += gen_cycle +pkg_gen_cycle_name = gen_cycle +pkg_gen_cycle_description = Simple, generic OTP behaviour for recurring tasks +pkg_gen_cycle_homepage = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_fetch = git +pkg_gen_cycle_repo = https://github.com/aerosol/gen_cycle +pkg_gen_cycle_commit = develop + +PACKAGES += gen_icmp +pkg_gen_icmp_name = gen_icmp +pkg_gen_icmp_description = Erlang interface to ICMP sockets +pkg_gen_icmp_homepage = https://github.com/msantos/gen_icmp +pkg_gen_icmp_fetch = git +pkg_gen_icmp_repo = https://github.com/msantos/gen_icmp +pkg_gen_icmp_commit = master + +PACKAGES += gen_nb_server +pkg_gen_nb_server_name = gen_nb_server +pkg_gen_nb_server_description = OTP behavior for writing non-blocking servers +pkg_gen_nb_server_homepage = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_fetch = git +pkg_gen_nb_server_repo = https://github.com/kevsmith/gen_nb_server +pkg_gen_nb_server_commit = master + +PACKAGES += gen_paxos +pkg_gen_paxos_name = gen_paxos +pkg_gen_paxos_description = An Erlang/OTP-style implementation of the PAXOS distributed consensus protocol +pkg_gen_paxos_homepage = https://github.com/gburd/gen_paxos +pkg_gen_paxos_fetch = git +pkg_gen_paxos_repo = https://github.com/gburd/gen_paxos +pkg_gen_paxos_commit = master + +PACKAGES += gen_smtp +pkg_gen_smtp_name = gen_smtp +pkg_gen_smtp_description = A generic Erlang SMTP server and client that can be extended via callback modules +pkg_gen_smtp_homepage = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_fetch = git +pkg_gen_smtp_repo = https://github.com/Vagabond/gen_smtp +pkg_gen_smtp_commit = master + +PACKAGES += gen_tracker +pkg_gen_tracker_name = gen_tracker +pkg_gen_tracker_description = supervisor with ets handling of children and their metadata +pkg_gen_tracker_homepage = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_fetch = git +pkg_gen_tracker_repo = https://github.com/erlyvideo/gen_tracker +pkg_gen_tracker_commit = master + +PACKAGES += gen_unix +pkg_gen_unix_name = gen_unix +pkg_gen_unix_description = Erlang Unix socket interface +pkg_gen_unix_homepage = https://github.com/msantos/gen_unix +pkg_gen_unix_fetch = git +pkg_gen_unix_repo = https://github.com/msantos/gen_unix +pkg_gen_unix_commit = master + +PACKAGES += geode +pkg_geode_name = geode +pkg_geode_description = geohash/proximity lookup in pure, uncut erlang. +pkg_geode_homepage = https://github.com/bradfordw/geode +pkg_geode_fetch = git +pkg_geode_repo = https://github.com/bradfordw/geode +pkg_geode_commit = master + +PACKAGES += getopt +pkg_getopt_name = getopt +pkg_getopt_description = Module to parse command line arguments using the GNU getopt syntax +pkg_getopt_homepage = https://github.com/jcomellas/getopt +pkg_getopt_fetch = git +pkg_getopt_repo = https://github.com/jcomellas/getopt +pkg_getopt_commit = master + +PACKAGES += gettext +pkg_gettext_name = gettext +pkg_gettext_description = Erlang internationalization library. +pkg_gettext_homepage = https://github.com/etnt/gettext +pkg_gettext_fetch = git +pkg_gettext_repo = https://github.com/etnt/gettext +pkg_gettext_commit = master + +PACKAGES += giallo +pkg_giallo_name = giallo +pkg_giallo_description = Small and flexible web framework on top of Cowboy +pkg_giallo_homepage = https://github.com/kivra/giallo +pkg_giallo_fetch = git +pkg_giallo_repo = https://github.com/kivra/giallo +pkg_giallo_commit = master + +PACKAGES += gin +pkg_gin_name = gin +pkg_gin_description = The guards and for Erlang parse_transform +pkg_gin_homepage = https://github.com/mad-cocktail/gin +pkg_gin_fetch = git +pkg_gin_repo = https://github.com/mad-cocktail/gin +pkg_gin_commit = master + +PACKAGES += gitty +pkg_gitty_name = gitty +pkg_gitty_description = Git access in erlang +pkg_gitty_homepage = https://github.com/maxlapshin/gitty +pkg_gitty_fetch = git +pkg_gitty_repo = https://github.com/maxlapshin/gitty +pkg_gitty_commit = master + +PACKAGES += gold_fever +pkg_gold_fever_name = gold_fever +pkg_gold_fever_description = A Treasure Hunt for Erlangers +pkg_gold_fever_homepage = https://github.com/inaka/gold_fever +pkg_gold_fever_fetch = git +pkg_gold_fever_repo = https://github.com/inaka/gold_fever +pkg_gold_fever_commit = master + +PACKAGES += gossiperl +pkg_gossiperl_name = gossiperl +pkg_gossiperl_description = Gossip middleware in Erlang +pkg_gossiperl_homepage = http://gossiperl.com/ +pkg_gossiperl_fetch = git +pkg_gossiperl_repo = https://github.com/gossiperl/gossiperl +pkg_gossiperl_commit = master + +PACKAGES += gpb +pkg_gpb_name = gpb +pkg_gpb_description = A Google Protobuf implementation for Erlang +pkg_gpb_homepage = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_fetch = git +pkg_gpb_repo = https://github.com/tomas-abrahamsson/gpb +pkg_gpb_commit = master + +PACKAGES += gproc +pkg_gproc_name = gproc +pkg_gproc_description = Extended process registry for Erlang +pkg_gproc_homepage = https://github.com/uwiger/gproc +pkg_gproc_fetch = git +pkg_gproc_repo = https://github.com/uwiger/gproc +pkg_gproc_commit = master + +PACKAGES += grapherl +pkg_grapherl_name = grapherl +pkg_grapherl_description = Create graphs of Erlang systems and programs +pkg_grapherl_homepage = https://github.com/eproxus/grapherl +pkg_grapherl_fetch = git +pkg_grapherl_repo = https://github.com/eproxus/grapherl +pkg_grapherl_commit = master + +PACKAGES += gun +pkg_gun_name = gun +pkg_gun_description = Asynchronous SPDY, HTTP and Websocket client written in Erlang. +pkg_gun_homepage = http//ninenines.eu +pkg_gun_fetch = git +pkg_gun_repo = https://github.com/ninenines/gun +pkg_gun_commit = master + +PACKAGES += gut +pkg_gut_name = gut +pkg_gut_description = gut is a template printing, aka scaffolding, tool for Erlang. Like rails generate or yeoman +pkg_gut_homepage = https://github.com/unbalancedparentheses/gut +pkg_gut_fetch = git +pkg_gut_repo = https://github.com/unbalancedparentheses/gut +pkg_gut_commit = master + +PACKAGES += hackney +pkg_hackney_name = hackney +pkg_hackney_description = simple HTTP client in Erlang +pkg_hackney_homepage = https://github.com/benoitc/hackney +pkg_hackney_fetch = git +pkg_hackney_repo = https://github.com/benoitc/hackney +pkg_hackney_commit = master + +PACKAGES += hamcrest +pkg_hamcrest_name = hamcrest +pkg_hamcrest_description = Erlang port of Hamcrest +pkg_hamcrest_homepage = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_fetch = git +pkg_hamcrest_repo = https://github.com/hyperthunk/hamcrest-erlang +pkg_hamcrest_commit = master + +PACKAGES += hanoidb +pkg_hanoidb_name = hanoidb +pkg_hanoidb_description = Erlang LSM BTree Storage +pkg_hanoidb_homepage = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_fetch = git +pkg_hanoidb_repo = https://github.com/krestenkrab/hanoidb +pkg_hanoidb_commit = master + +PACKAGES += hottub +pkg_hottub_name = hottub +pkg_hottub_description = Permanent Erlang Worker Pool +pkg_hottub_homepage = https://github.com/bfrog/hottub +pkg_hottub_fetch = git +pkg_hottub_repo = https://github.com/bfrog/hottub +pkg_hottub_commit = master + +PACKAGES += hpack +pkg_hpack_name = hpack +pkg_hpack_description = HPACK Implementation for Erlang +pkg_hpack_homepage = https://github.com/joedevivo/hpack +pkg_hpack_fetch = git +pkg_hpack_repo = https://github.com/joedevivo/hpack +pkg_hpack_commit = master + +PACKAGES += hyper +pkg_hyper_name = hyper +pkg_hyper_description = Erlang implementation of HyperLogLog +pkg_hyper_homepage = https://github.com/GameAnalytics/hyper +pkg_hyper_fetch = git +pkg_hyper_repo = https://github.com/GameAnalytics/hyper +pkg_hyper_commit = master + +PACKAGES += i18n +pkg_i18n_name = i18n +pkg_i18n_description = International components for unicode from Erlang (unicode, date, string, number, format, locale, localization, transliteration, icu4e) +pkg_i18n_homepage = https://github.com/erlang-unicode/i18n +pkg_i18n_fetch = git +pkg_i18n_repo = https://github.com/erlang-unicode/i18n +pkg_i18n_commit = master + +PACKAGES += ibrowse +pkg_ibrowse_name = ibrowse +pkg_ibrowse_description = Erlang HTTP client +pkg_ibrowse_homepage = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_fetch = git +pkg_ibrowse_repo = https://github.com/cmullaparthi/ibrowse +pkg_ibrowse_commit = master + +PACKAGES += ierlang +pkg_ierlang_name = ierlang +pkg_ierlang_description = An Erlang language kernel for IPython. +pkg_ierlang_homepage = https://github.com/robbielynch/ierlang +pkg_ierlang_fetch = git +pkg_ierlang_repo = https://github.com/robbielynch/ierlang +pkg_ierlang_commit = master + +PACKAGES += iota +pkg_iota_name = iota +pkg_iota_description = iota (Inter-dependency Objective Testing Apparatus) - a tool to enforce clean separation of responsibilities in Erlang code +pkg_iota_homepage = https://github.com/jpgneves/iota +pkg_iota_fetch = git +pkg_iota_repo = https://github.com/jpgneves/iota +pkg_iota_commit = master + +PACKAGES += irc_lib +pkg_irc_lib_name = irc_lib +pkg_irc_lib_description = Erlang irc client library +pkg_irc_lib_homepage = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_fetch = git +pkg_irc_lib_repo = https://github.com/OtpChatBot/irc_lib +pkg_irc_lib_commit = master + +PACKAGES += ircd +pkg_ircd_name = ircd +pkg_ircd_description = A pluggable IRC daemon application/library for Erlang. +pkg_ircd_homepage = https://github.com/tonyg/erlang-ircd +pkg_ircd_fetch = git +pkg_ircd_repo = https://github.com/tonyg/erlang-ircd +pkg_ircd_commit = master + +PACKAGES += iris +pkg_iris_name = iris +pkg_iris_description = Iris Erlang binding +pkg_iris_homepage = https://github.com/project-iris/iris-erl +pkg_iris_fetch = git +pkg_iris_repo = https://github.com/project-iris/iris-erl +pkg_iris_commit = master + +PACKAGES += iso8601 +pkg_iso8601_name = iso8601 +pkg_iso8601_description = Erlang ISO 8601 date formatter/parser +pkg_iso8601_homepage = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_fetch = git +pkg_iso8601_repo = https://github.com/seansawyer/erlang_iso8601 +pkg_iso8601_commit = master + +PACKAGES += jamdb_sybase +pkg_jamdb_sybase_name = jamdb_sybase +pkg_jamdb_sybase_description = Erlang driver for SAP Sybase ASE +pkg_jamdb_sybase_homepage = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_fetch = git +pkg_jamdb_sybase_repo = https://github.com/erlangbureau/jamdb_sybase +pkg_jamdb_sybase_commit = master + +PACKAGES += jerg +pkg_jerg_name = jerg +pkg_jerg_description = JSON Schema to Erlang Records Generator +pkg_jerg_homepage = https://github.com/ddossot/jerg +pkg_jerg_fetch = git +pkg_jerg_repo = https://github.com/ddossot/jerg +pkg_jerg_commit = master + +PACKAGES += jesse +pkg_jesse_name = jesse +pkg_jesse_description = jesse (JSon Schema Erlang) is an implementation of a json schema validator for Erlang. +pkg_jesse_homepage = https://github.com/for-GET/jesse +pkg_jesse_fetch = git +pkg_jesse_repo = https://github.com/for-GET/jesse +pkg_jesse_commit = master + +PACKAGES += jiffy_v +pkg_jiffy_v_name = jiffy_v +pkg_jiffy_v_description = JSON validation utility +pkg_jiffy_v_homepage = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_fetch = git +pkg_jiffy_v_repo = https://github.com/shizzard/jiffy-v +pkg_jiffy_v_commit = master + +PACKAGES += jiffy +pkg_jiffy_name = jiffy +pkg_jiffy_description = JSON NIFs for Erlang. +pkg_jiffy_homepage = https://github.com/davisp/jiffy +pkg_jiffy_fetch = git +pkg_jiffy_repo = https://github.com/davisp/jiffy +pkg_jiffy_commit = master + +PACKAGES += jobs +pkg_jobs_name = jobs +pkg_jobs_description = a Job scheduler for load regulation +pkg_jobs_homepage = https://github.com/esl/jobs +pkg_jobs_fetch = git +pkg_jobs_repo = https://github.com/esl/jobs +pkg_jobs_commit = master + +PACKAGES += joxa +pkg_joxa_name = joxa +pkg_joxa_description = A Modern Lisp for the Erlang VM +pkg_joxa_homepage = https://github.com/joxa/joxa +pkg_joxa_fetch = git +pkg_joxa_repo = https://github.com/joxa/joxa +pkg_joxa_commit = master + +PACKAGES += json_rec +pkg_json_rec_name = json_rec +pkg_json_rec_description = JSON to erlang record +pkg_json_rec_homepage = https://github.com/justinkirby/json_rec +pkg_json_rec_fetch = git +pkg_json_rec_repo = https://github.com/justinkirby/json_rec +pkg_json_rec_commit = master + +PACKAGES += json +pkg_json_name = json +pkg_json_description = a high level json library for erlang (17.0+) +pkg_json_homepage = https://github.com/talentdeficit/json +pkg_json_fetch = git +pkg_json_repo = https://github.com/talentdeficit/json +pkg_json_commit = master + +PACKAGES += jsone +pkg_jsone_name = jsone +pkg_jsone_description = An Erlang library for encoding, decoding JSON data. +pkg_jsone_homepage = https://github.com/sile/jsone.git +pkg_jsone_fetch = git +pkg_jsone_repo = https://github.com/sile/jsone.git +pkg_jsone_commit = master + +PACKAGES += jsonerl +pkg_jsonerl_name = jsonerl +pkg_jsonerl_description = yet another but slightly different erlang <-> json encoder/decoder +pkg_jsonerl_homepage = https://github.com/lambder/jsonerl +pkg_jsonerl_fetch = git +pkg_jsonerl_repo = https://github.com/lambder/jsonerl +pkg_jsonerl_commit = master + +PACKAGES += jsonpath +pkg_jsonpath_name = jsonpath +pkg_jsonpath_description = Fast Erlang JSON data retrieval and updates via javascript-like notation +pkg_jsonpath_homepage = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_fetch = git +pkg_jsonpath_repo = https://github.com/GeneStevens/jsonpath +pkg_jsonpath_commit = master + +PACKAGES += jsonx +pkg_jsonx_name = jsonx +pkg_jsonx_description = JSONX is an Erlang library for efficient decode and encode JSON, written in C. +pkg_jsonx_homepage = https://github.com/iskra/jsonx +pkg_jsonx_fetch = git +pkg_jsonx_repo = https://github.com/iskra/jsonx +pkg_jsonx_commit = master + +PACKAGES += jsx +pkg_jsx_name = jsx +pkg_jsx_description = An Erlang application for consuming, producing and manipulating JSON. +pkg_jsx_homepage = https://github.com/talentdeficit/jsx +pkg_jsx_fetch = git +pkg_jsx_repo = https://github.com/talentdeficit/jsx +pkg_jsx_commit = master + +PACKAGES += kafka_protocol +pkg_kafka_protocol_name = kafka_protocol +pkg_kafka_protocol_description = Kafka protocol Erlang library +pkg_kafka_protocol_homepage = https://github.com/klarna/kafka_protocol +pkg_kafka_protocol_fetch = git +pkg_kafka_protocol_repo = https://github.com/klarna/kafka_protocol.git +pkg_kafka_protocol_commit = master + +PACKAGES += kafka +pkg_kafka_name = kafka +pkg_kafka_description = Kafka consumer and producer in Erlang +pkg_kafka_homepage = https://github.com/wooga/kafka-erlang +pkg_kafka_fetch = git +pkg_kafka_repo = https://github.com/wooga/kafka-erlang +pkg_kafka_commit = master + +PACKAGES += kai +pkg_kai_name = kai +pkg_kai_description = DHT storage by Takeshi Inoue +pkg_kai_homepage = https://github.com/synrc/kai +pkg_kai_fetch = git +pkg_kai_repo = https://github.com/synrc/kai +pkg_kai_commit = master + +PACKAGES += katja +pkg_katja_name = katja +pkg_katja_description = A simple Riemann client written in Erlang. +pkg_katja_homepage = https://github.com/nifoc/katja +pkg_katja_fetch = git +pkg_katja_repo = https://github.com/nifoc/katja +pkg_katja_commit = master + +PACKAGES += kdht +pkg_kdht_name = kdht +pkg_kdht_description = kdht is an erlang DHT implementation +pkg_kdht_homepage = https://github.com/kevinlynx/kdht +pkg_kdht_fetch = git +pkg_kdht_repo = https://github.com/kevinlynx/kdht +pkg_kdht_commit = master + +PACKAGES += key2value +pkg_key2value_name = key2value +pkg_key2value_description = Erlang 2-way map +pkg_key2value_homepage = https://github.com/okeuday/key2value +pkg_key2value_fetch = git +pkg_key2value_repo = https://github.com/okeuday/key2value +pkg_key2value_commit = master + +PACKAGES += keys1value +pkg_keys1value_name = keys1value +pkg_keys1value_description = Erlang set associative map for key lists +pkg_keys1value_homepage = https://github.com/okeuday/keys1value +pkg_keys1value_fetch = git +pkg_keys1value_repo = https://github.com/okeuday/keys1value +pkg_keys1value_commit = master + +PACKAGES += kinetic +pkg_kinetic_name = kinetic +pkg_kinetic_description = Erlang Kinesis Client +pkg_kinetic_homepage = https://github.com/AdRoll/kinetic +pkg_kinetic_fetch = git +pkg_kinetic_repo = https://github.com/AdRoll/kinetic +pkg_kinetic_commit = master + +PACKAGES += kjell +pkg_kjell_name = kjell +pkg_kjell_description = Erlang Shell +pkg_kjell_homepage = https://github.com/karlll/kjell +pkg_kjell_fetch = git +pkg_kjell_repo = https://github.com/karlll/kjell +pkg_kjell_commit = master + +PACKAGES += kraken +pkg_kraken_name = kraken +pkg_kraken_description = Distributed Pubsub Server for Realtime Apps +pkg_kraken_homepage = https://github.com/Asana/kraken +pkg_kraken_fetch = git +pkg_kraken_repo = https://github.com/Asana/kraken +pkg_kraken_commit = master + +PACKAGES += kucumberl +pkg_kucumberl_name = kucumberl +pkg_kucumberl_description = A pure-erlang, open-source, implementation of Cucumber +pkg_kucumberl_homepage = https://github.com/openshine/kucumberl +pkg_kucumberl_fetch = git +pkg_kucumberl_repo = https://github.com/openshine/kucumberl +pkg_kucumberl_commit = master + +PACKAGES += kvc +pkg_kvc_name = kvc +pkg_kvc_description = KVC - Key Value Coding for Erlang data structures +pkg_kvc_homepage = https://github.com/etrepum/kvc +pkg_kvc_fetch = git +pkg_kvc_repo = https://github.com/etrepum/kvc +pkg_kvc_commit = master + +PACKAGES += kvlists +pkg_kvlists_name = kvlists +pkg_kvlists_description = Lists of key-value pairs (decoded JSON) in Erlang +pkg_kvlists_homepage = https://github.com/jcomellas/kvlists +pkg_kvlists_fetch = git +pkg_kvlists_repo = https://github.com/jcomellas/kvlists +pkg_kvlists_commit = master + +PACKAGES += kvs +pkg_kvs_name = kvs +pkg_kvs_description = Container and Iterator +pkg_kvs_homepage = https://github.com/synrc/kvs +pkg_kvs_fetch = git +pkg_kvs_repo = https://github.com/synrc/kvs +pkg_kvs_commit = master + +PACKAGES += lager_amqp_backend +pkg_lager_amqp_backend_name = lager_amqp_backend +pkg_lager_amqp_backend_description = AMQP RabbitMQ Lager backend +pkg_lager_amqp_backend_homepage = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_fetch = git +pkg_lager_amqp_backend_repo = https://github.com/jbrisbin/lager_amqp_backend +pkg_lager_amqp_backend_commit = master + +PACKAGES += lager_syslog +pkg_lager_syslog_name = lager_syslog +pkg_lager_syslog_description = Syslog backend for lager +pkg_lager_syslog_homepage = https://github.com/basho/lager_syslog +pkg_lager_syslog_fetch = git +pkg_lager_syslog_repo = https://github.com/basho/lager_syslog +pkg_lager_syslog_commit = master + +PACKAGES += lager +pkg_lager_name = lager +pkg_lager_description = A logging framework for Erlang/OTP. +pkg_lager_homepage = https://github.com/basho/lager +pkg_lager_fetch = git +pkg_lager_repo = https://github.com/basho/lager +pkg_lager_commit = master + +PACKAGES += lambdapad +pkg_lambdapad_name = lambdapad +pkg_lambdapad_description = Static site generator using Erlang. Yes, Erlang. +pkg_lambdapad_homepage = https://github.com/gar1t/lambdapad +pkg_lambdapad_fetch = git +pkg_lambdapad_repo = https://github.com/gar1t/lambdapad +pkg_lambdapad_commit = master + +PACKAGES += lasp +pkg_lasp_name = lasp +pkg_lasp_description = A Language for Distributed, Eventually Consistent Computations +pkg_lasp_homepage = http://lasp-lang.org/ +pkg_lasp_fetch = git +pkg_lasp_repo = https://github.com/lasp-lang/lasp +pkg_lasp_commit = master + +PACKAGES += lasse +pkg_lasse_name = lasse +pkg_lasse_description = SSE handler for Cowboy +pkg_lasse_homepage = https://github.com/inaka/lasse +pkg_lasse_fetch = git +pkg_lasse_repo = https://github.com/inaka/lasse +pkg_lasse_commit = master + +PACKAGES += ldap +pkg_ldap_name = ldap +pkg_ldap_description = LDAP server written in Erlang +pkg_ldap_homepage = https://github.com/spawnproc/ldap +pkg_ldap_fetch = git +pkg_ldap_repo = https://github.com/spawnproc/ldap +pkg_ldap_commit = master + +PACKAGES += lethink +pkg_lethink_name = lethink +pkg_lethink_description = erlang driver for rethinkdb +pkg_lethink_homepage = https://github.com/taybin/lethink +pkg_lethink_fetch = git +pkg_lethink_repo = https://github.com/taybin/lethink +pkg_lethink_commit = master + +PACKAGES += lfe +pkg_lfe_name = lfe +pkg_lfe_description = Lisp Flavoured Erlang (LFE) +pkg_lfe_homepage = https://github.com/rvirding/lfe +pkg_lfe_fetch = git +pkg_lfe_repo = https://github.com/rvirding/lfe +pkg_lfe_commit = master + +PACKAGES += ling +pkg_ling_name = ling +pkg_ling_description = Erlang on Xen +pkg_ling_homepage = https://github.com/cloudozer/ling +pkg_ling_fetch = git +pkg_ling_repo = https://github.com/cloudozer/ling +pkg_ling_commit = master + +PACKAGES += live +pkg_live_name = live +pkg_live_description = Automated module and configuration reloader. +pkg_live_homepage = http://ninenines.eu +pkg_live_fetch = git +pkg_live_repo = https://github.com/ninenines/live +pkg_live_commit = master + +PACKAGES += lmq +pkg_lmq_name = lmq +pkg_lmq_description = Lightweight Message Queue +pkg_lmq_homepage = https://github.com/iij/lmq +pkg_lmq_fetch = git +pkg_lmq_repo = https://github.com/iij/lmq +pkg_lmq_commit = master + +PACKAGES += locker +pkg_locker_name = locker +pkg_locker_description = Atomic distributed 'check and set' for short-lived keys +pkg_locker_homepage = https://github.com/wooga/locker +pkg_locker_fetch = git +pkg_locker_repo = https://github.com/wooga/locker +pkg_locker_commit = master + +PACKAGES += locks +pkg_locks_name = locks +pkg_locks_description = A scalable, deadlock-resolving resource locker +pkg_locks_homepage = https://github.com/uwiger/locks +pkg_locks_fetch = git +pkg_locks_repo = https://github.com/uwiger/locks +pkg_locks_commit = master + +PACKAGES += log4erl +pkg_log4erl_name = log4erl +pkg_log4erl_description = A logger for erlang in the spirit of Log4J. +pkg_log4erl_homepage = https://github.com/ahmednawras/log4erl +pkg_log4erl_fetch = git +pkg_log4erl_repo = https://github.com/ahmednawras/log4erl +pkg_log4erl_commit = master + +PACKAGES += lol +pkg_lol_name = lol +pkg_lol_description = Lisp on erLang, and programming is fun again +pkg_lol_homepage = https://github.com/b0oh/lol +pkg_lol_fetch = git +pkg_lol_repo = https://github.com/b0oh/lol +pkg_lol_commit = master + +PACKAGES += lucid +pkg_lucid_name = lucid +pkg_lucid_description = HTTP/2 server written in Erlang +pkg_lucid_homepage = https://github.com/tatsuhiro-t/lucid +pkg_lucid_fetch = git +pkg_lucid_repo = https://github.com/tatsuhiro-t/lucid +pkg_lucid_commit = master + +PACKAGES += luerl +pkg_luerl_name = luerl +pkg_luerl_description = Lua in Erlang +pkg_luerl_homepage = https://github.com/rvirding/luerl +pkg_luerl_fetch = git +pkg_luerl_repo = https://github.com/rvirding/luerl +pkg_luerl_commit = develop + +PACKAGES += luwak +pkg_luwak_name = luwak +pkg_luwak_description = Large-object storage interface for Riak +pkg_luwak_homepage = https://github.com/basho/luwak +pkg_luwak_fetch = git +pkg_luwak_repo = https://github.com/basho/luwak +pkg_luwak_commit = master + +PACKAGES += lux +pkg_lux_name = lux +pkg_lux_description = Lux (LUcid eXpect scripting) simplifies test automation and provides an Expect-style execution of commands +pkg_lux_homepage = https://github.com/hawk/lux +pkg_lux_fetch = git +pkg_lux_repo = https://github.com/hawk/lux +pkg_lux_commit = master + +PACKAGES += machi +pkg_machi_name = machi +pkg_machi_description = Machi file store +pkg_machi_homepage = https://github.com/basho/machi +pkg_machi_fetch = git +pkg_machi_repo = https://github.com/basho/machi +pkg_machi_commit = master + +PACKAGES += mad +pkg_mad_name = mad +pkg_mad_description = Small and Fast Rebar Replacement +pkg_mad_homepage = https://github.com/synrc/mad +pkg_mad_fetch = git +pkg_mad_repo = https://github.com/synrc/mad +pkg_mad_commit = master + +PACKAGES += marina +pkg_marina_name = marina +pkg_marina_description = Non-blocking Erlang Cassandra CQL3 client +pkg_marina_homepage = https://github.com/lpgauth/marina +pkg_marina_fetch = git +pkg_marina_repo = https://github.com/lpgauth/marina +pkg_marina_commit = master + +PACKAGES += mavg +pkg_mavg_name = mavg +pkg_mavg_description = Erlang :: Exponential moving average library +pkg_mavg_homepage = https://github.com/EchoTeam/mavg +pkg_mavg_fetch = git +pkg_mavg_repo = https://github.com/EchoTeam/mavg +pkg_mavg_commit = master + +PACKAGES += mc_erl +pkg_mc_erl_name = mc_erl +pkg_mc_erl_description = mc-erl is a server for Minecraft 1.4.7 written in Erlang. +pkg_mc_erl_homepage = https://github.com/clonejo/mc-erl +pkg_mc_erl_fetch = git +pkg_mc_erl_repo = https://github.com/clonejo/mc-erl +pkg_mc_erl_commit = master + +PACKAGES += mcd +pkg_mcd_name = mcd +pkg_mcd_description = Fast memcached protocol client in pure Erlang +pkg_mcd_homepage = https://github.com/EchoTeam/mcd +pkg_mcd_fetch = git +pkg_mcd_repo = https://github.com/EchoTeam/mcd +pkg_mcd_commit = master + +PACKAGES += mcerlang +pkg_mcerlang_name = mcerlang +pkg_mcerlang_description = The McErlang model checker for Erlang +pkg_mcerlang_homepage = https://github.com/fredlund/McErlang +pkg_mcerlang_fetch = git +pkg_mcerlang_repo = https://github.com/fredlund/McErlang +pkg_mcerlang_commit = master + +PACKAGES += meck +pkg_meck_name = meck +pkg_meck_description = A mocking library for Erlang +pkg_meck_homepage = https://github.com/eproxus/meck +pkg_meck_fetch = git +pkg_meck_repo = https://github.com/eproxus/meck +pkg_meck_commit = master + +PACKAGES += mekao +pkg_mekao_name = mekao +pkg_mekao_description = SQL constructor +pkg_mekao_homepage = https://github.com/ddosia/mekao +pkg_mekao_fetch = git +pkg_mekao_repo = https://github.com/ddosia/mekao +pkg_mekao_commit = master + +PACKAGES += memo +pkg_memo_name = memo +pkg_memo_description = Erlang memoization server +pkg_memo_homepage = https://github.com/tuncer/memo +pkg_memo_fetch = git +pkg_memo_repo = https://github.com/tuncer/memo +pkg_memo_commit = master + +PACKAGES += merge_index +pkg_merge_index_name = merge_index +pkg_merge_index_description = MergeIndex is an Erlang library for storing ordered sets on disk. It is very similar to an SSTable (in Google's Bigtable) or an HFile (in Hadoop). +pkg_merge_index_homepage = https://github.com/basho/merge_index +pkg_merge_index_fetch = git +pkg_merge_index_repo = https://github.com/basho/merge_index +pkg_merge_index_commit = master + +PACKAGES += merl +pkg_merl_name = merl +pkg_merl_description = Metaprogramming in Erlang +pkg_merl_homepage = https://github.com/richcarl/merl +pkg_merl_fetch = git +pkg_merl_repo = https://github.com/richcarl/merl +pkg_merl_commit = master + +PACKAGES += mimerl +pkg_mimerl_name = mimerl +pkg_mimerl_description = library to handle mimetypes +pkg_mimerl_homepage = https://github.com/benoitc/mimerl +pkg_mimerl_fetch = git +pkg_mimerl_repo = https://github.com/benoitc/mimerl +pkg_mimerl_commit = master + +PACKAGES += mimetypes +pkg_mimetypes_name = mimetypes +pkg_mimetypes_description = Erlang MIME types library +pkg_mimetypes_homepage = https://github.com/spawngrid/mimetypes +pkg_mimetypes_fetch = git +pkg_mimetypes_repo = https://github.com/spawngrid/mimetypes +pkg_mimetypes_commit = master + +PACKAGES += mixer +pkg_mixer_name = mixer +pkg_mixer_description = Mix in functions from other modules +pkg_mixer_homepage = https://github.com/chef/mixer +pkg_mixer_fetch = git +pkg_mixer_repo = https://github.com/chef/mixer +pkg_mixer_commit = master + +PACKAGES += mochiweb_xpath +pkg_mochiweb_xpath_name = mochiweb_xpath +pkg_mochiweb_xpath_description = XPath support for mochiweb's html parser +pkg_mochiweb_xpath_homepage = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_fetch = git +pkg_mochiweb_xpath_repo = https://github.com/retnuh/mochiweb_xpath +pkg_mochiweb_xpath_commit = master + +PACKAGES += mochiweb +pkg_mochiweb_name = mochiweb +pkg_mochiweb_description = MochiWeb is an Erlang library for building lightweight HTTP servers. +pkg_mochiweb_homepage = https://github.com/mochi/mochiweb +pkg_mochiweb_fetch = git +pkg_mochiweb_repo = https://github.com/mochi/mochiweb +pkg_mochiweb_commit = master + +PACKAGES += mockgyver +pkg_mockgyver_name = mockgyver +pkg_mockgyver_description = A mocking library for Erlang +pkg_mockgyver_homepage = https://github.com/klajo/mockgyver +pkg_mockgyver_fetch = git +pkg_mockgyver_repo = https://github.com/klajo/mockgyver +pkg_mockgyver_commit = master + +PACKAGES += modlib +pkg_modlib_name = modlib +pkg_modlib_description = Web framework based on Erlang's inets httpd +pkg_modlib_homepage = https://github.com/gar1t/modlib +pkg_modlib_fetch = git +pkg_modlib_repo = https://github.com/gar1t/modlib +pkg_modlib_commit = master + +PACKAGES += mongodb +pkg_mongodb_name = mongodb +pkg_mongodb_description = MongoDB driver for Erlang +pkg_mongodb_homepage = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_fetch = git +pkg_mongodb_repo = https://github.com/comtihon/mongodb-erlang +pkg_mongodb_commit = master + +PACKAGES += mongooseim +pkg_mongooseim_name = mongooseim +pkg_mongooseim_description = Jabber / XMPP server with focus on performance and scalability, by Erlang Solutions +pkg_mongooseim_homepage = https://www.erlang-solutions.com/products/mongooseim-massively-scalable-ejabberd-platform +pkg_mongooseim_fetch = git +pkg_mongooseim_repo = https://github.com/esl/MongooseIM +pkg_mongooseim_commit = master + +PACKAGES += moyo +pkg_moyo_name = moyo +pkg_moyo_description = Erlang utility functions library +pkg_moyo_homepage = https://github.com/dwango/moyo +pkg_moyo_fetch = git +pkg_moyo_repo = https://github.com/dwango/moyo +pkg_moyo_commit = master + +PACKAGES += msgpack +pkg_msgpack_name = msgpack +pkg_msgpack_description = MessagePack (de)serializer implementation for Erlang +pkg_msgpack_homepage = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_fetch = git +pkg_msgpack_repo = https://github.com/msgpack/msgpack-erlang +pkg_msgpack_commit = master + +PACKAGES += mu2 +pkg_mu2_name = mu2 +pkg_mu2_description = Erlang mutation testing tool +pkg_mu2_homepage = https://github.com/ramsay-t/mu2 +pkg_mu2_fetch = git +pkg_mu2_repo = https://github.com/ramsay-t/mu2 +pkg_mu2_commit = master + +PACKAGES += mustache +pkg_mustache_name = mustache +pkg_mustache_description = Mustache template engine for Erlang. +pkg_mustache_homepage = https://github.com/mojombo/mustache.erl +pkg_mustache_fetch = git +pkg_mustache_repo = https://github.com/mojombo/mustache.erl +pkg_mustache_commit = master + +PACKAGES += myproto +pkg_myproto_name = myproto +pkg_myproto_description = MySQL Server Protocol in Erlang +pkg_myproto_homepage = https://github.com/altenwald/myproto +pkg_myproto_fetch = git +pkg_myproto_repo = https://github.com/altenwald/myproto +pkg_myproto_commit = master + +PACKAGES += mysql +pkg_mysql_name = mysql +pkg_mysql_description = Erlang MySQL Driver (from code.google.com) +pkg_mysql_homepage = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_fetch = git +pkg_mysql_repo = https://github.com/dizzyd/erlang-mysql-driver +pkg_mysql_commit = master + +PACKAGES += n2o +pkg_n2o_name = n2o +pkg_n2o_description = WebSocket Application Server +pkg_n2o_homepage = https://github.com/5HT/n2o +pkg_n2o_fetch = git +pkg_n2o_repo = https://github.com/5HT/n2o +pkg_n2o_commit = master + +PACKAGES += nat_upnp +pkg_nat_upnp_name = nat_upnp +pkg_nat_upnp_description = Erlang library to map your internal port to an external using UNP IGD +pkg_nat_upnp_homepage = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_fetch = git +pkg_nat_upnp_repo = https://github.com/benoitc/nat_upnp +pkg_nat_upnp_commit = master + +PACKAGES += neo4j +pkg_neo4j_name = neo4j +pkg_neo4j_description = Erlang client library for Neo4J. +pkg_neo4j_homepage = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_fetch = git +pkg_neo4j_repo = https://github.com/dmitriid/neo4j-erlang +pkg_neo4j_commit = master + +PACKAGES += neotoma +pkg_neotoma_name = neotoma +pkg_neotoma_description = Erlang library and packrat parser-generator for parsing expression grammars. +pkg_neotoma_homepage = https://github.com/seancribbs/neotoma +pkg_neotoma_fetch = git +pkg_neotoma_repo = https://github.com/seancribbs/neotoma +pkg_neotoma_commit = master + +PACKAGES += newrelic +pkg_newrelic_name = newrelic +pkg_newrelic_description = Erlang library for sending metrics to New Relic +pkg_newrelic_homepage = https://github.com/wooga/newrelic-erlang +pkg_newrelic_fetch = git +pkg_newrelic_repo = https://github.com/wooga/newrelic-erlang +pkg_newrelic_commit = master + +PACKAGES += nifty +pkg_nifty_name = nifty +pkg_nifty_description = Erlang NIF wrapper generator +pkg_nifty_homepage = https://github.com/parapluu/nifty +pkg_nifty_fetch = git +pkg_nifty_repo = https://github.com/parapluu/nifty +pkg_nifty_commit = master + +PACKAGES += nitrogen_core +pkg_nitrogen_core_name = nitrogen_core +pkg_nitrogen_core_description = The core Nitrogen library. +pkg_nitrogen_core_homepage = http://nitrogenproject.com/ +pkg_nitrogen_core_fetch = git +pkg_nitrogen_core_repo = https://github.com/nitrogen/nitrogen_core +pkg_nitrogen_core_commit = master + +PACKAGES += nkbase +pkg_nkbase_name = nkbase +pkg_nkbase_description = NkBASE distributed database +pkg_nkbase_homepage = https://github.com/Nekso/nkbase +pkg_nkbase_fetch = git +pkg_nkbase_repo = https://github.com/Nekso/nkbase +pkg_nkbase_commit = develop + +PACKAGES += nkdocker +pkg_nkdocker_name = nkdocker +pkg_nkdocker_description = Erlang Docker client +pkg_nkdocker_homepage = https://github.com/Nekso/nkdocker +pkg_nkdocker_fetch = git +pkg_nkdocker_repo = https://github.com/Nekso/nkdocker +pkg_nkdocker_commit = master + +PACKAGES += nkpacket +pkg_nkpacket_name = nkpacket +pkg_nkpacket_description = Generic Erlang transport layer +pkg_nkpacket_homepage = https://github.com/Nekso/nkpacket +pkg_nkpacket_fetch = git +pkg_nkpacket_repo = https://github.com/Nekso/nkpacket +pkg_nkpacket_commit = master + +PACKAGES += nksip +pkg_nksip_name = nksip +pkg_nksip_description = Erlang SIP application server +pkg_nksip_homepage = https://github.com/kalta/nksip +pkg_nksip_fetch = git +pkg_nksip_repo = https://github.com/kalta/nksip +pkg_nksip_commit = master + +PACKAGES += nodefinder +pkg_nodefinder_name = nodefinder +pkg_nodefinder_description = automatic node discovery via UDP multicast +pkg_nodefinder_homepage = https://github.com/erlanger/nodefinder +pkg_nodefinder_fetch = git +pkg_nodefinder_repo = https://github.com/okeuday/nodefinder +pkg_nodefinder_commit = master + +PACKAGES += nprocreg +pkg_nprocreg_name = nprocreg +pkg_nprocreg_description = Minimal Distributed Erlang Process Registry +pkg_nprocreg_homepage = http://nitrogenproject.com/ +pkg_nprocreg_fetch = git +pkg_nprocreg_repo = https://github.com/nitrogen/nprocreg +pkg_nprocreg_commit = master + +PACKAGES += oauth +pkg_oauth_name = oauth +pkg_oauth_description = An Erlang OAuth 1.0 implementation +pkg_oauth_homepage = https://github.com/tim/erlang-oauth +pkg_oauth_fetch = git +pkg_oauth_repo = https://github.com/tim/erlang-oauth +pkg_oauth_commit = master + +PACKAGES += oauth2 +pkg_oauth2_name = oauth2 +pkg_oauth2_description = Erlang Oauth2 implementation +pkg_oauth2_homepage = https://github.com/kivra/oauth2 +pkg_oauth2_fetch = git +pkg_oauth2_repo = https://github.com/kivra/oauth2 +pkg_oauth2_commit = master + +PACKAGES += octopus +pkg_octopus_name = octopus +pkg_octopus_description = Small and flexible pool manager written in Erlang +pkg_octopus_homepage = https://github.com/erlangbureau/octopus +pkg_octopus_fetch = git +pkg_octopus_repo = https://github.com/erlangbureau/octopus +pkg_octopus_commit = master + +PACKAGES += of_protocol +pkg_of_protocol_name = of_protocol +pkg_of_protocol_description = OpenFlow Protocol Library for Erlang +pkg_of_protocol_homepage = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_fetch = git +pkg_of_protocol_repo = https://github.com/FlowForwarding/of_protocol +pkg_of_protocol_commit = master + +PACKAGES += opencouch +pkg_opencouch_name = couch +pkg_opencouch_description = A embeddable document oriented database compatible with Apache CouchDB +pkg_opencouch_homepage = https://github.com/benoitc/opencouch +pkg_opencouch_fetch = git +pkg_opencouch_repo = https://github.com/benoitc/opencouch +pkg_opencouch_commit = master + +PACKAGES += openflow +pkg_openflow_name = openflow +pkg_openflow_description = An OpenFlow controller written in pure erlang +pkg_openflow_homepage = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_fetch = git +pkg_openflow_repo = https://github.com/renatoaguiar/erlang-openflow +pkg_openflow_commit = master + +PACKAGES += openid +pkg_openid_name = openid +pkg_openid_description = Erlang OpenID +pkg_openid_homepage = https://github.com/brendonh/erl_openid +pkg_openid_fetch = git +pkg_openid_repo = https://github.com/brendonh/erl_openid +pkg_openid_commit = master + +PACKAGES += openpoker +pkg_openpoker_name = openpoker +pkg_openpoker_description = Genesis Texas hold'em Game Server +pkg_openpoker_homepage = https://github.com/hpyhacking/openpoker +pkg_openpoker_fetch = git +pkg_openpoker_repo = https://github.com/hpyhacking/openpoker +pkg_openpoker_commit = master + +PACKAGES += pal +pkg_pal_name = pal +pkg_pal_description = Pragmatic Authentication Library +pkg_pal_homepage = https://github.com/manifest/pal +pkg_pal_fetch = git +pkg_pal_repo = https://github.com/manifest/pal +pkg_pal_commit = master + +PACKAGES += parse_trans +pkg_parse_trans_name = parse_trans +pkg_parse_trans_description = Parse transform utilities for Erlang +pkg_parse_trans_homepage = https://github.com/uwiger/parse_trans +pkg_parse_trans_fetch = git +pkg_parse_trans_repo = https://github.com/uwiger/parse_trans +pkg_parse_trans_commit = master + +PACKAGES += parsexml +pkg_parsexml_name = parsexml +pkg_parsexml_description = Simple DOM XML parser with convenient and very simple API +pkg_parsexml_homepage = https://github.com/maxlapshin/parsexml +pkg_parsexml_fetch = git +pkg_parsexml_repo = https://github.com/maxlapshin/parsexml +pkg_parsexml_commit = master + +PACKAGES += pegjs +pkg_pegjs_name = pegjs +pkg_pegjs_description = An implementation of PEG.js grammar for Erlang. +pkg_pegjs_homepage = https://github.com/dmitriid/pegjs +pkg_pegjs_fetch = git +pkg_pegjs_repo = https://github.com/dmitriid/pegjs +pkg_pegjs_commit = master + +PACKAGES += percept2 +pkg_percept2_name = percept2 +pkg_percept2_description = Concurrent profiling tool for Erlang +pkg_percept2_homepage = https://github.com/huiqing/percept2 +pkg_percept2_fetch = git +pkg_percept2_repo = https://github.com/huiqing/percept2 +pkg_percept2_commit = master + +PACKAGES += pgsql +pkg_pgsql_name = pgsql +pkg_pgsql_description = Erlang PostgreSQL driver +pkg_pgsql_homepage = https://github.com/semiocast/pgsql +pkg_pgsql_fetch = git +pkg_pgsql_repo = https://github.com/semiocast/pgsql +pkg_pgsql_commit = master + +PACKAGES += pkgx +pkg_pkgx_name = pkgx +pkg_pkgx_description = Build .deb packages from Erlang releases +pkg_pkgx_homepage = https://github.com/arjan/pkgx +pkg_pkgx_fetch = git +pkg_pkgx_repo = https://github.com/arjan/pkgx +pkg_pkgx_commit = master + +PACKAGES += pkt +pkg_pkt_name = pkt +pkg_pkt_description = Erlang network protocol library +pkg_pkt_homepage = https://github.com/msantos/pkt +pkg_pkt_fetch = git +pkg_pkt_repo = https://github.com/msantos/pkt +pkg_pkt_commit = master + +PACKAGES += plain_fsm +pkg_plain_fsm_name = plain_fsm +pkg_plain_fsm_description = A behaviour/support library for writing plain Erlang FSMs. +pkg_plain_fsm_homepage = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_fetch = git +pkg_plain_fsm_repo = https://github.com/uwiger/plain_fsm +pkg_plain_fsm_commit = master + +PACKAGES += plumtree +pkg_plumtree_name = plumtree +pkg_plumtree_description = Epidemic Broadcast Trees +pkg_plumtree_homepage = https://github.com/helium/plumtree +pkg_plumtree_fetch = git +pkg_plumtree_repo = https://github.com/helium/plumtree +pkg_plumtree_commit = master + +PACKAGES += pmod_transform +pkg_pmod_transform_name = pmod_transform +pkg_pmod_transform_description = Parse transform for parameterized modules +pkg_pmod_transform_homepage = https://github.com/erlang/pmod_transform +pkg_pmod_transform_fetch = git +pkg_pmod_transform_repo = https://github.com/erlang/pmod_transform +pkg_pmod_transform_commit = master + +PACKAGES += pobox +pkg_pobox_name = pobox +pkg_pobox_description = External buffer processes to protect against mailbox overflow in Erlang +pkg_pobox_homepage = https://github.com/ferd/pobox +pkg_pobox_fetch = git +pkg_pobox_repo = https://github.com/ferd/pobox +pkg_pobox_commit = master + +PACKAGES += ponos +pkg_ponos_name = ponos +pkg_ponos_description = ponos is a simple yet powerful load generator written in erlang +pkg_ponos_homepage = https://github.com/klarna/ponos +pkg_ponos_fetch = git +pkg_ponos_repo = https://github.com/klarna/ponos +pkg_ponos_commit = master + +PACKAGES += poolboy +pkg_poolboy_name = poolboy +pkg_poolboy_description = A hunky Erlang worker pool factory +pkg_poolboy_homepage = https://github.com/devinus/poolboy +pkg_poolboy_fetch = git +pkg_poolboy_repo = https://github.com/devinus/poolboy +pkg_poolboy_commit = master + +PACKAGES += pooler +pkg_pooler_name = pooler +pkg_pooler_description = An OTP Process Pool Application +pkg_pooler_homepage = https://github.com/seth/pooler +pkg_pooler_fetch = git +pkg_pooler_repo = https://github.com/seth/pooler +pkg_pooler_commit = master + +PACKAGES += pqueue +pkg_pqueue_name = pqueue +pkg_pqueue_description = Erlang Priority Queues +pkg_pqueue_homepage = https://github.com/okeuday/pqueue +pkg_pqueue_fetch = git +pkg_pqueue_repo = https://github.com/okeuday/pqueue +pkg_pqueue_commit = master + +PACKAGES += procket +pkg_procket_name = procket +pkg_procket_description = Erlang interface to low level socket operations +pkg_procket_homepage = http://blog.listincomprehension.com/search/label/procket +pkg_procket_fetch = git +pkg_procket_repo = https://github.com/msantos/procket +pkg_procket_commit = master + +PACKAGES += prop +pkg_prop_name = prop +pkg_prop_description = An Erlang code scaffolding and generator system. +pkg_prop_homepage = https://github.com/nuex/prop +pkg_prop_fetch = git +pkg_prop_repo = https://github.com/nuex/prop +pkg_prop_commit = master + +PACKAGES += proper +pkg_proper_name = proper +pkg_proper_description = PropEr: a QuickCheck-inspired property-based testing tool for Erlang. +pkg_proper_homepage = http://proper.softlab.ntua.gr +pkg_proper_fetch = git +pkg_proper_repo = https://github.com/manopapad/proper +pkg_proper_commit = master + +PACKAGES += props +pkg_props_name = props +pkg_props_description = Property structure library +pkg_props_homepage = https://github.com/greyarea/props +pkg_props_fetch = git +pkg_props_repo = https://github.com/greyarea/props +pkg_props_commit = master + +PACKAGES += protobuffs +pkg_protobuffs_name = protobuffs +pkg_protobuffs_description = An implementation of Google's Protocol Buffers for Erlang, based on ngerakines/erlang_protobuffs. +pkg_protobuffs_homepage = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_fetch = git +pkg_protobuffs_repo = https://github.com/basho/erlang_protobuffs +pkg_protobuffs_commit = master + +PACKAGES += psycho +pkg_psycho_name = psycho +pkg_psycho_description = HTTP server that provides a WSGI-like interface for applications and middleware. +pkg_psycho_homepage = https://github.com/gar1t/psycho +pkg_psycho_fetch = git +pkg_psycho_repo = https://github.com/gar1t/psycho +pkg_psycho_commit = master + +PACKAGES += purity +pkg_purity_name = purity +pkg_purity_description = A side-effect analyzer for Erlang +pkg_purity_homepage = https://github.com/mpitid/purity +pkg_purity_fetch = git +pkg_purity_repo = https://github.com/mpitid/purity +pkg_purity_commit = master + +PACKAGES += push_service +pkg_push_service_name = push_service +pkg_push_service_description = Push service +pkg_push_service_homepage = https://github.com/hairyhum/push_service +pkg_push_service_fetch = git +pkg_push_service_repo = https://github.com/hairyhum/push_service +pkg_push_service_commit = master + +PACKAGES += qdate +pkg_qdate_name = qdate +pkg_qdate_description = Date, time, and timezone parsing, formatting, and conversion for Erlang. +pkg_qdate_homepage = https://github.com/choptastic/qdate +pkg_qdate_fetch = git +pkg_qdate_repo = https://github.com/choptastic/qdate +pkg_qdate_commit = master + +PACKAGES += qrcode +pkg_qrcode_name = qrcode +pkg_qrcode_description = QR Code encoder in Erlang +pkg_qrcode_homepage = https://github.com/komone/qrcode +pkg_qrcode_fetch = git +pkg_qrcode_repo = https://github.com/komone/qrcode +pkg_qrcode_commit = master + +PACKAGES += quest +pkg_quest_name = quest +pkg_quest_description = Learn Erlang through this set of challenges. An interactive system for getting to know Erlang. +pkg_quest_homepage = https://github.com/eriksoe/ErlangQuest +pkg_quest_fetch = git +pkg_quest_repo = https://github.com/eriksoe/ErlangQuest +pkg_quest_commit = master + +PACKAGES += quickrand +pkg_quickrand_name = quickrand +pkg_quickrand_description = Quick Erlang Random Number Generation +pkg_quickrand_homepage = https://github.com/okeuday/quickrand +pkg_quickrand_fetch = git +pkg_quickrand_repo = https://github.com/okeuday/quickrand +pkg_quickrand_commit = master + +PACKAGES += rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_name = rabbit_exchange_type_riak +pkg_rabbit_exchange_type_riak_description = Custom RabbitMQ exchange type for sticking messages in Riak +pkg_rabbit_exchange_type_riak_homepage = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_fetch = git +pkg_rabbit_exchange_type_riak_repo = https://github.com/jbrisbin/riak-exchange +pkg_rabbit_exchange_type_riak_commit = master + +PACKAGES += rabbit +pkg_rabbit_name = rabbit +pkg_rabbit_description = RabbitMQ Server +pkg_rabbit_homepage = https://www.rabbitmq.com/ +pkg_rabbit_fetch = git +pkg_rabbit_repo = https://github.com/rabbitmq/rabbitmq-server.git +pkg_rabbit_commit = master + +PACKAGES += rack +pkg_rack_name = rack +pkg_rack_description = Rack handler for erlang +pkg_rack_homepage = https://github.com/erlyvideo/rack +pkg_rack_fetch = git +pkg_rack_repo = https://github.com/erlyvideo/rack +pkg_rack_commit = master + +PACKAGES += radierl +pkg_radierl_name = radierl +pkg_radierl_description = RADIUS protocol stack implemented in Erlang. +pkg_radierl_homepage = https://github.com/vances/radierl +pkg_radierl_fetch = git +pkg_radierl_repo = https://github.com/vances/radierl +pkg_radierl_commit = master + +PACKAGES += rafter +pkg_rafter_name = rafter +pkg_rafter_description = An Erlang library application which implements the Raft consensus protocol +pkg_rafter_homepage = https://github.com/andrewjstone/rafter +pkg_rafter_fetch = git +pkg_rafter_repo = https://github.com/andrewjstone/rafter +pkg_rafter_commit = master + +PACKAGES += ranch +pkg_ranch_name = ranch +pkg_ranch_description = Socket acceptor pool for TCP protocols. +pkg_ranch_homepage = http://ninenines.eu +pkg_ranch_fetch = git +pkg_ranch_repo = https://github.com/ninenines/ranch +pkg_ranch_commit = 1.2.1 + +PACKAGES += rbeacon +pkg_rbeacon_name = rbeacon +pkg_rbeacon_description = LAN discovery and presence in Erlang. +pkg_rbeacon_homepage = https://github.com/refuge/rbeacon +pkg_rbeacon_fetch = git +pkg_rbeacon_repo = https://github.com/refuge/rbeacon +pkg_rbeacon_commit = master + +PACKAGES += rebar +pkg_rebar_name = rebar +pkg_rebar_description = Erlang build tool that makes it easy to compile and test Erlang applications, port drivers and releases. +pkg_rebar_homepage = http://www.rebar3.org +pkg_rebar_fetch = git +pkg_rebar_repo = https://github.com/rebar/rebar3 +pkg_rebar_commit = master + +PACKAGES += rebus +pkg_rebus_name = rebus +pkg_rebus_description = A stupid simple, internal, pub/sub event bus written in- and for Erlang. +pkg_rebus_homepage = https://github.com/olle/rebus +pkg_rebus_fetch = git +pkg_rebus_repo = https://github.com/olle/rebus +pkg_rebus_commit = master + +PACKAGES += rec2json +pkg_rec2json_name = rec2json +pkg_rec2json_description = Compile erlang record definitions into modules to convert them to/from json easily. +pkg_rec2json_homepage = https://github.com/lordnull/rec2json +pkg_rec2json_fetch = git +pkg_rec2json_repo = https://github.com/lordnull/rec2json +pkg_rec2json_commit = master + +PACKAGES += recon +pkg_recon_name = recon +pkg_recon_description = Collection of functions and scripts to debug Erlang in production. +pkg_recon_homepage = https://github.com/ferd/recon +pkg_recon_fetch = git +pkg_recon_repo = https://github.com/ferd/recon +pkg_recon_commit = master + +PACKAGES += record_info +pkg_record_info_name = record_info +pkg_record_info_description = Convert between record and proplist +pkg_record_info_homepage = https://github.com/bipthelin/erlang-record_info +pkg_record_info_fetch = git +pkg_record_info_repo = https://github.com/bipthelin/erlang-record_info +pkg_record_info_commit = master + +PACKAGES += redgrid +pkg_redgrid_name = redgrid +pkg_redgrid_description = automatic Erlang node discovery via redis +pkg_redgrid_homepage = https://github.com/jkvor/redgrid +pkg_redgrid_fetch = git +pkg_redgrid_repo = https://github.com/jkvor/redgrid +pkg_redgrid_commit = master + +PACKAGES += redo +pkg_redo_name = redo +pkg_redo_description = pipelined erlang redis client +pkg_redo_homepage = https://github.com/jkvor/redo +pkg_redo_fetch = git +pkg_redo_repo = https://github.com/jkvor/redo +pkg_redo_commit = master + +PACKAGES += reload_mk +pkg_reload_mk_name = reload_mk +pkg_reload_mk_description = Live reload plugin for erlang.mk. +pkg_reload_mk_homepage = https://github.com/bullno1/reload.mk +pkg_reload_mk_fetch = git +pkg_reload_mk_repo = https://github.com/bullno1/reload.mk +pkg_reload_mk_commit = master + +PACKAGES += reltool_util +pkg_reltool_util_name = reltool_util +pkg_reltool_util_description = Erlang reltool utility functionality application +pkg_reltool_util_homepage = https://github.com/okeuday/reltool_util +pkg_reltool_util_fetch = git +pkg_reltool_util_repo = https://github.com/okeuday/reltool_util +pkg_reltool_util_commit = master + +PACKAGES += relx +pkg_relx_name = relx +pkg_relx_description = Sane, simple release creation for Erlang +pkg_relx_homepage = https://github.com/erlware/relx +pkg_relx_fetch = git +pkg_relx_repo = https://github.com/erlware/relx +pkg_relx_commit = master + +PACKAGES += resource_discovery +pkg_resource_discovery_name = resource_discovery +pkg_resource_discovery_description = An application used to dynamically discover resources present in an Erlang node cluster. +pkg_resource_discovery_homepage = http://erlware.org/ +pkg_resource_discovery_fetch = git +pkg_resource_discovery_repo = https://github.com/erlware/resource_discovery +pkg_resource_discovery_commit = master + +PACKAGES += restc +pkg_restc_name = restc +pkg_restc_description = Erlang Rest Client +pkg_restc_homepage = https://github.com/kivra/restclient +pkg_restc_fetch = git +pkg_restc_repo = https://github.com/kivra/restclient +pkg_restc_commit = master + +PACKAGES += rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_name = rfc4627_jsonrpc +pkg_rfc4627_jsonrpc_description = Erlang RFC4627 (JSON) codec and JSON-RPC server implementation. +pkg_rfc4627_jsonrpc_homepage = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_fetch = git +pkg_rfc4627_jsonrpc_repo = https://github.com/tonyg/erlang-rfc4627 +pkg_rfc4627_jsonrpc_commit = master + +PACKAGES += riak_control +pkg_riak_control_name = riak_control +pkg_riak_control_description = Webmachine-based administration interface for Riak. +pkg_riak_control_homepage = https://github.com/basho/riak_control +pkg_riak_control_fetch = git +pkg_riak_control_repo = https://github.com/basho/riak_control +pkg_riak_control_commit = master + +PACKAGES += riak_core +pkg_riak_core_name = riak_core +pkg_riak_core_description = Distributed systems infrastructure used by Riak. +pkg_riak_core_homepage = https://github.com/basho/riak_core +pkg_riak_core_fetch = git +pkg_riak_core_repo = https://github.com/basho/riak_core +pkg_riak_core_commit = master + +PACKAGES += riak_dt +pkg_riak_dt_name = riak_dt +pkg_riak_dt_description = Convergent replicated datatypes in Erlang +pkg_riak_dt_homepage = https://github.com/basho/riak_dt +pkg_riak_dt_fetch = git +pkg_riak_dt_repo = https://github.com/basho/riak_dt +pkg_riak_dt_commit = master + +PACKAGES += riak_ensemble +pkg_riak_ensemble_name = riak_ensemble +pkg_riak_ensemble_description = Multi-Paxos framework in Erlang +pkg_riak_ensemble_homepage = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_fetch = git +pkg_riak_ensemble_repo = https://github.com/basho/riak_ensemble +pkg_riak_ensemble_commit = master + +PACKAGES += riak_kv +pkg_riak_kv_name = riak_kv +pkg_riak_kv_description = Riak Key/Value Store +pkg_riak_kv_homepage = https://github.com/basho/riak_kv +pkg_riak_kv_fetch = git +pkg_riak_kv_repo = https://github.com/basho/riak_kv +pkg_riak_kv_commit = master + +PACKAGES += riak_pg +pkg_riak_pg_name = riak_pg +pkg_riak_pg_description = Distributed process groups with riak_core. +pkg_riak_pg_homepage = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_fetch = git +pkg_riak_pg_repo = https://github.com/cmeiklejohn/riak_pg +pkg_riak_pg_commit = master + +PACKAGES += riak_pipe +pkg_riak_pipe_name = riak_pipe +pkg_riak_pipe_description = Riak Pipelines +pkg_riak_pipe_homepage = https://github.com/basho/riak_pipe +pkg_riak_pipe_fetch = git +pkg_riak_pipe_repo = https://github.com/basho/riak_pipe +pkg_riak_pipe_commit = master + +PACKAGES += riak_sysmon +pkg_riak_sysmon_name = riak_sysmon +pkg_riak_sysmon_description = Simple OTP app for managing Erlang VM system_monitor event messages +pkg_riak_sysmon_homepage = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_fetch = git +pkg_riak_sysmon_repo = https://github.com/basho/riak_sysmon +pkg_riak_sysmon_commit = master + +PACKAGES += riak_test +pkg_riak_test_name = riak_test +pkg_riak_test_description = I'm in your cluster, testing your riaks +pkg_riak_test_homepage = https://github.com/basho/riak_test +pkg_riak_test_fetch = git +pkg_riak_test_repo = https://github.com/basho/riak_test +pkg_riak_test_commit = master + +PACKAGES += riakc +pkg_riakc_name = riakc +pkg_riakc_description = Erlang clients for Riak. +pkg_riakc_homepage = https://github.com/basho/riak-erlang-client +pkg_riakc_fetch = git +pkg_riakc_repo = https://github.com/basho/riak-erlang-client +pkg_riakc_commit = master + +PACKAGES += riakhttpc +pkg_riakhttpc_name = riakhttpc +pkg_riakhttpc_description = Riak Erlang client using the HTTP interface +pkg_riakhttpc_homepage = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_fetch = git +pkg_riakhttpc_repo = https://github.com/basho/riak-erlang-http-client +pkg_riakhttpc_commit = master + +PACKAGES += riaknostic +pkg_riaknostic_name = riaknostic +pkg_riaknostic_description = A diagnostic tool for Riak installations, to find common errors asap +pkg_riaknostic_homepage = https://github.com/basho/riaknostic +pkg_riaknostic_fetch = git +pkg_riaknostic_repo = https://github.com/basho/riaknostic +pkg_riaknostic_commit = master + +PACKAGES += riakpool +pkg_riakpool_name = riakpool +pkg_riakpool_description = erlang riak client pool +pkg_riakpool_homepage = https://github.com/dweldon/riakpool +pkg_riakpool_fetch = git +pkg_riakpool_repo = https://github.com/dweldon/riakpool +pkg_riakpool_commit = master + +PACKAGES += rivus_cep +pkg_rivus_cep_name = rivus_cep +pkg_rivus_cep_description = Complex event processing in Erlang +pkg_rivus_cep_homepage = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_fetch = git +pkg_rivus_cep_repo = https://github.com/vascokk/rivus_cep +pkg_rivus_cep_commit = master + +PACKAGES += rlimit +pkg_rlimit_name = rlimit +pkg_rlimit_description = Magnus Klaar's rate limiter code from etorrent +pkg_rlimit_homepage = https://github.com/jlouis/rlimit +pkg_rlimit_fetch = git +pkg_rlimit_repo = https://github.com/jlouis/rlimit +pkg_rlimit_commit = master + +PACKAGES += rust_mk +pkg_rust_mk_name = rust_mk +pkg_rust_mk_description = Build Rust crates in an Erlang application +pkg_rust_mk_homepage = https://github.com/goertzenator/rust.mk +pkg_rust_mk_fetch = git +pkg_rust_mk_repo = https://github.com/goertzenator/rust.mk +pkg_rust_mk_commit = master + +PACKAGES += safetyvalve +pkg_safetyvalve_name = safetyvalve +pkg_safetyvalve_description = A safety valve for your erlang node +pkg_safetyvalve_homepage = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_fetch = git +pkg_safetyvalve_repo = https://github.com/jlouis/safetyvalve +pkg_safetyvalve_commit = master + +PACKAGES += seestar +pkg_seestar_name = seestar +pkg_seestar_description = The Erlang client for Cassandra 1.2+ binary protocol +pkg_seestar_homepage = https://github.com/iamaleksey/seestar +pkg_seestar_fetch = git +pkg_seestar_repo = https://github.com/iamaleksey/seestar +pkg_seestar_commit = master + +PACKAGES += service +pkg_service_name = service +pkg_service_description = A minimal Erlang behavior for creating CloudI internal services +pkg_service_homepage = http://cloudi.org/ +pkg_service_fetch = git +pkg_service_repo = https://github.com/CloudI/service +pkg_service_commit = master + +PACKAGES += setup +pkg_setup_name = setup +pkg_setup_description = Generic setup utility for Erlang-based systems +pkg_setup_homepage = https://github.com/uwiger/setup +pkg_setup_fetch = git +pkg_setup_repo = https://github.com/uwiger/setup +pkg_setup_commit = master + +PACKAGES += sext +pkg_sext_name = sext +pkg_sext_description = Sortable Erlang Term Serialization +pkg_sext_homepage = https://github.com/uwiger/sext +pkg_sext_fetch = git +pkg_sext_repo = https://github.com/uwiger/sext +pkg_sext_commit = master + +PACKAGES += sfmt +pkg_sfmt_name = sfmt +pkg_sfmt_description = SFMT pseudo random number generator for Erlang. +pkg_sfmt_homepage = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_fetch = git +pkg_sfmt_repo = https://github.com/jj1bdx/sfmt-erlang +pkg_sfmt_commit = master + +PACKAGES += sgte +pkg_sgte_name = sgte +pkg_sgte_description = A simple Erlang Template Engine +pkg_sgte_homepage = https://github.com/filippo/sgte +pkg_sgte_fetch = git +pkg_sgte_repo = https://github.com/filippo/sgte +pkg_sgte_commit = master + +PACKAGES += sheriff +pkg_sheriff_name = sheriff +pkg_sheriff_description = Parse transform for type based validation. +pkg_sheriff_homepage = http://ninenines.eu +pkg_sheriff_fetch = git +pkg_sheriff_repo = https://github.com/extend/sheriff +pkg_sheriff_commit = master + +PACKAGES += shotgun +pkg_shotgun_name = shotgun +pkg_shotgun_description = better than just a gun +pkg_shotgun_homepage = https://github.com/inaka/shotgun +pkg_shotgun_fetch = git +pkg_shotgun_repo = https://github.com/inaka/shotgun +pkg_shotgun_commit = master + +PACKAGES += sidejob +pkg_sidejob_name = sidejob +pkg_sidejob_description = Parallel worker and capacity limiting library for Erlang +pkg_sidejob_homepage = https://github.com/basho/sidejob +pkg_sidejob_fetch = git +pkg_sidejob_repo = https://github.com/basho/sidejob +pkg_sidejob_commit = master + +PACKAGES += sieve +pkg_sieve_name = sieve +pkg_sieve_description = sieve is a simple TCP routing proxy (layer 7) in erlang +pkg_sieve_homepage = https://github.com/benoitc/sieve +pkg_sieve_fetch = git +pkg_sieve_repo = https://github.com/benoitc/sieve +pkg_sieve_commit = master + +PACKAGES += sighandler +pkg_sighandler_name = sighandler +pkg_sighandler_description = Handle UNIX signals in Er lang +pkg_sighandler_homepage = https://github.com/jkingsbery/sighandler +pkg_sighandler_fetch = git +pkg_sighandler_repo = https://github.com/jkingsbery/sighandler +pkg_sighandler_commit = master + +PACKAGES += simhash +pkg_simhash_name = simhash +pkg_simhash_description = Simhashing for Erlang -- hashing algorithm to find near-duplicates in binary data. +pkg_simhash_homepage = https://github.com/ferd/simhash +pkg_simhash_fetch = git +pkg_simhash_repo = https://github.com/ferd/simhash +pkg_simhash_commit = master + +PACKAGES += simple_bridge +pkg_simple_bridge_name = simple_bridge +pkg_simple_bridge_description = A simple, standardized interface library to Erlang HTTP Servers. +pkg_simple_bridge_homepage = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_fetch = git +pkg_simple_bridge_repo = https://github.com/nitrogen/simple_bridge +pkg_simple_bridge_commit = master + +PACKAGES += simple_oauth2 +pkg_simple_oauth2_name = simple_oauth2 +pkg_simple_oauth2_description = Simple erlang OAuth2 client module for any http server framework (Google, Facebook, Yandex, Vkontakte are preconfigured) +pkg_simple_oauth2_homepage = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_fetch = git +pkg_simple_oauth2_repo = https://github.com/virtan/simple_oauth2 +pkg_simple_oauth2_commit = master + +PACKAGES += skel +pkg_skel_name = skel +pkg_skel_description = A Streaming Process-based Skeleton Library for Erlang +pkg_skel_homepage = https://github.com/ParaPhrase/skel +pkg_skel_fetch = git +pkg_skel_repo = https://github.com/ParaPhrase/skel +pkg_skel_commit = master + +PACKAGES += slack +pkg_slack_name = slack +pkg_slack_description = Minimal slack notification OTP library. +pkg_slack_homepage = https://github.com/DonBranson/slack +pkg_slack_fetch = git +pkg_slack_repo = https://github.com/DonBranson/slack.git +pkg_slack_commit = master + +PACKAGES += smother +pkg_smother_name = smother +pkg_smother_description = Extended code coverage metrics for Erlang. +pkg_smother_homepage = https://ramsay-t.github.io/Smother/ +pkg_smother_fetch = git +pkg_smother_repo = https://github.com/ramsay-t/Smother +pkg_smother_commit = master + +PACKAGES += social +pkg_social_name = social +pkg_social_description = Cowboy handler for social login via OAuth2 providers +pkg_social_homepage = https://github.com/dvv/social +pkg_social_fetch = git +pkg_social_repo = https://github.com/dvv/social +pkg_social_commit = master + +PACKAGES += spapi_router +pkg_spapi_router_name = spapi_router +pkg_spapi_router_description = Partially-connected Erlang clustering +pkg_spapi_router_homepage = https://github.com/spilgames/spapi-router +pkg_spapi_router_fetch = git +pkg_spapi_router_repo = https://github.com/spilgames/spapi-router +pkg_spapi_router_commit = master + +PACKAGES += sqerl +pkg_sqerl_name = sqerl +pkg_sqerl_description = An Erlang-flavoured SQL DSL +pkg_sqerl_homepage = https://github.com/hairyhum/sqerl +pkg_sqerl_fetch = git +pkg_sqerl_repo = https://github.com/hairyhum/sqerl +pkg_sqerl_commit = master + +PACKAGES += srly +pkg_srly_name = srly +pkg_srly_description = Native Erlang Unix serial interface +pkg_srly_homepage = https://github.com/msantos/srly +pkg_srly_fetch = git +pkg_srly_repo = https://github.com/msantos/srly +pkg_srly_commit = master + +PACKAGES += sshrpc +pkg_sshrpc_name = sshrpc +pkg_sshrpc_description = Erlang SSH RPC module (experimental) +pkg_sshrpc_homepage = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_fetch = git +pkg_sshrpc_repo = https://github.com/jj1bdx/sshrpc +pkg_sshrpc_commit = master + +PACKAGES += stable +pkg_stable_name = stable +pkg_stable_description = Library of assorted helpers for Cowboy web server. +pkg_stable_homepage = https://github.com/dvv/stable +pkg_stable_fetch = git +pkg_stable_repo = https://github.com/dvv/stable +pkg_stable_commit = master + +PACKAGES += statebox_riak +pkg_statebox_riak_name = statebox_riak +pkg_statebox_riak_description = Convenience library that makes it easier to use statebox with riak, extracted from best practices in our production code at Mochi Media. +pkg_statebox_riak_homepage = https://github.com/mochi/statebox_riak +pkg_statebox_riak_fetch = git +pkg_statebox_riak_repo = https://github.com/mochi/statebox_riak +pkg_statebox_riak_commit = master + +PACKAGES += statebox +pkg_statebox_name = statebox +pkg_statebox_description = Erlang state monad with merge/conflict-resolution capabilities. Useful for Riak. +pkg_statebox_homepage = https://github.com/mochi/statebox +pkg_statebox_fetch = git +pkg_statebox_repo = https://github.com/mochi/statebox +pkg_statebox_commit = master + +PACKAGES += statman +pkg_statman_name = statman +pkg_statman_description = Efficiently collect massive volumes of metrics inside the Erlang VM +pkg_statman_homepage = https://github.com/knutin/statman +pkg_statman_fetch = git +pkg_statman_repo = https://github.com/knutin/statman +pkg_statman_commit = master + +PACKAGES += statsderl +pkg_statsderl_name = statsderl +pkg_statsderl_description = StatsD client (erlang) +pkg_statsderl_homepage = https://github.com/lpgauth/statsderl +pkg_statsderl_fetch = git +pkg_statsderl_repo = https://github.com/lpgauth/statsderl +pkg_statsderl_commit = master + +PACKAGES += stdinout_pool +pkg_stdinout_pool_name = stdinout_pool +pkg_stdinout_pool_description = stdinout_pool : stuff goes in, stuff goes out. there's never any miscommunication. +pkg_stdinout_pool_homepage = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_fetch = git +pkg_stdinout_pool_repo = https://github.com/mattsta/erlang-stdinout-pool +pkg_stdinout_pool_commit = master + +PACKAGES += stockdb +pkg_stockdb_name = stockdb +pkg_stockdb_description = Database for storing Stock Exchange quotes in erlang +pkg_stockdb_homepage = https://github.com/maxlapshin/stockdb +pkg_stockdb_fetch = git +pkg_stockdb_repo = https://github.com/maxlapshin/stockdb +pkg_stockdb_commit = master + +PACKAGES += stripe +pkg_stripe_name = stripe +pkg_stripe_description = Erlang interface to the stripe.com API +pkg_stripe_homepage = https://github.com/mattsta/stripe-erlang +pkg_stripe_fetch = git +pkg_stripe_repo = https://github.com/mattsta/stripe-erlang +pkg_stripe_commit = v1 + +PACKAGES += supervisor3 +pkg_supervisor3_name = supervisor3 +pkg_supervisor3_description = OTP supervisor with additional strategies +pkg_supervisor3_homepage = https://github.com/klarna/supervisor3 +pkg_supervisor3_fetch = git +pkg_supervisor3_repo = https://github.com/klarna/supervisor3.git +pkg_supervisor3_commit = master + +PACKAGES += surrogate +pkg_surrogate_name = surrogate +pkg_surrogate_description = Proxy server written in erlang. Supports reverse proxy load balancing and forward proxy with http (including CONNECT), socks4, socks5, and transparent proxy modes. +pkg_surrogate_homepage = https://github.com/skruger/Surrogate +pkg_surrogate_fetch = git +pkg_surrogate_repo = https://github.com/skruger/Surrogate +pkg_surrogate_commit = master + +PACKAGES += swab +pkg_swab_name = swab +pkg_swab_description = General purpose buffer handling module +pkg_swab_homepage = https://github.com/crownedgrouse/swab +pkg_swab_fetch = git +pkg_swab_repo = https://github.com/crownedgrouse/swab +pkg_swab_commit = master + +PACKAGES += swarm +pkg_swarm_name = swarm +pkg_swarm_description = Fast and simple acceptor pool for Erlang +pkg_swarm_homepage = https://github.com/jeremey/swarm +pkg_swarm_fetch = git +pkg_swarm_repo = https://github.com/jeremey/swarm +pkg_swarm_commit = master + +PACKAGES += switchboard +pkg_switchboard_name = switchboard +pkg_switchboard_description = A framework for processing email using worker plugins. +pkg_switchboard_homepage = https://github.com/thusfresh/switchboard +pkg_switchboard_fetch = git +pkg_switchboard_repo = https://github.com/thusfresh/switchboard +pkg_switchboard_commit = master + +PACKAGES += syn +pkg_syn_name = syn +pkg_syn_description = A global Process Registry and Process Group manager for Erlang. +pkg_syn_homepage = https://github.com/ostinelli/syn +pkg_syn_fetch = git +pkg_syn_repo = https://github.com/ostinelli/syn +pkg_syn_commit = master + +PACKAGES += sync +pkg_sync_name = sync +pkg_sync_description = On-the-fly recompiling and reloading in Erlang. +pkg_sync_homepage = https://github.com/rustyio/sync +pkg_sync_fetch = git +pkg_sync_repo = https://github.com/rustyio/sync +pkg_sync_commit = master + +PACKAGES += syntaxerl +pkg_syntaxerl_name = syntaxerl +pkg_syntaxerl_description = Syntax checker for Erlang +pkg_syntaxerl_homepage = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_fetch = git +pkg_syntaxerl_repo = https://github.com/ten0s/syntaxerl +pkg_syntaxerl_commit = master + +PACKAGES += syslog +pkg_syslog_name = syslog +pkg_syslog_description = Erlang port driver for interacting with syslog via syslog(3) +pkg_syslog_homepage = https://github.com/Vagabond/erlang-syslog +pkg_syslog_fetch = git +pkg_syslog_repo = https://github.com/Vagabond/erlang-syslog +pkg_syslog_commit = master + +PACKAGES += taskforce +pkg_taskforce_name = taskforce +pkg_taskforce_description = Erlang worker pools for controlled parallelisation of arbitrary tasks. +pkg_taskforce_homepage = https://github.com/g-andrade/taskforce +pkg_taskforce_fetch = git +pkg_taskforce_repo = https://github.com/g-andrade/taskforce +pkg_taskforce_commit = master + +PACKAGES += tddreloader +pkg_tddreloader_name = tddreloader +pkg_tddreloader_description = Shell utility for recompiling, reloading, and testing code as it changes +pkg_tddreloader_homepage = https://github.com/version2beta/tddreloader +pkg_tddreloader_fetch = git +pkg_tddreloader_repo = https://github.com/version2beta/tddreloader +pkg_tddreloader_commit = master + +PACKAGES += tempo +pkg_tempo_name = tempo +pkg_tempo_description = NIF-based date and time parsing and formatting for Erlang. +pkg_tempo_homepage = https://github.com/selectel/tempo +pkg_tempo_fetch = git +pkg_tempo_repo = https://github.com/selectel/tempo +pkg_tempo_commit = master + +PACKAGES += ticktick +pkg_ticktick_name = ticktick +pkg_ticktick_description = Ticktick is an id generator for message service. +pkg_ticktick_homepage = https://github.com/ericliang/ticktick +pkg_ticktick_fetch = git +pkg_ticktick_repo = https://github.com/ericliang/ticktick +pkg_ticktick_commit = master + +PACKAGES += tinymq +pkg_tinymq_name = tinymq +pkg_tinymq_description = TinyMQ - a diminutive, in-memory message queue +pkg_tinymq_homepage = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_fetch = git +pkg_tinymq_repo = https://github.com/ChicagoBoss/tinymq +pkg_tinymq_commit = master + +PACKAGES += tinymt +pkg_tinymt_name = tinymt +pkg_tinymt_description = TinyMT pseudo random number generator for Erlang. +pkg_tinymt_homepage = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_fetch = git +pkg_tinymt_repo = https://github.com/jj1bdx/tinymt-erlang +pkg_tinymt_commit = master + +PACKAGES += tirerl +pkg_tirerl_name = tirerl +pkg_tirerl_description = Erlang interface to Elastic Search +pkg_tirerl_homepage = https://github.com/inaka/tirerl +pkg_tirerl_fetch = git +pkg_tirerl_repo = https://github.com/inaka/tirerl +pkg_tirerl_commit = master + +PACKAGES += traffic_tools +pkg_traffic_tools_name = traffic_tools +pkg_traffic_tools_description = Simple traffic limiting library +pkg_traffic_tools_homepage = https://github.com/systra/traffic_tools +pkg_traffic_tools_fetch = git +pkg_traffic_tools_repo = https://github.com/systra/traffic_tools +pkg_traffic_tools_commit = master + +PACKAGES += trails +pkg_trails_name = trails +pkg_trails_description = A couple of improvements over Cowboy Routes +pkg_trails_homepage = http://inaka.github.io/cowboy-trails/ +pkg_trails_fetch = git +pkg_trails_repo = https://github.com/inaka/cowboy-trails +pkg_trails_commit = master + +PACKAGES += trane +pkg_trane_name = trane +pkg_trane_description = SAX style broken HTML parser in Erlang +pkg_trane_homepage = https://github.com/massemanet/trane +pkg_trane_fetch = git +pkg_trane_repo = https://github.com/massemanet/trane +pkg_trane_commit = master + +PACKAGES += transit +pkg_transit_name = transit +pkg_transit_description = transit format for erlang +pkg_transit_homepage = https://github.com/isaiah/transit-erlang +pkg_transit_fetch = git +pkg_transit_repo = https://github.com/isaiah/transit-erlang +pkg_transit_commit = master + +PACKAGES += trie +pkg_trie_name = trie +pkg_trie_description = Erlang Trie Implementation +pkg_trie_homepage = https://github.com/okeuday/trie +pkg_trie_fetch = git +pkg_trie_repo = https://github.com/okeuday/trie +pkg_trie_commit = master + +PACKAGES += triq +pkg_triq_name = triq +pkg_triq_description = Trifork QuickCheck +pkg_triq_homepage = https://github.com/krestenkrab/triq +pkg_triq_fetch = git +pkg_triq_repo = https://github.com/krestenkrab/triq +pkg_triq_commit = master + +PACKAGES += tunctl +pkg_tunctl_name = tunctl +pkg_tunctl_description = Erlang TUN/TAP interface +pkg_tunctl_homepage = https://github.com/msantos/tunctl +pkg_tunctl_fetch = git +pkg_tunctl_repo = https://github.com/msantos/tunctl +pkg_tunctl_commit = master + +PACKAGES += twerl +pkg_twerl_name = twerl +pkg_twerl_description = Erlang client for the Twitter Streaming API +pkg_twerl_homepage = https://github.com/lucaspiller/twerl +pkg_twerl_fetch = git +pkg_twerl_repo = https://github.com/lucaspiller/twerl +pkg_twerl_commit = oauth + +PACKAGES += twitter_erlang +pkg_twitter_erlang_name = twitter_erlang +pkg_twitter_erlang_description = An Erlang twitter client +pkg_twitter_erlang_homepage = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_fetch = git +pkg_twitter_erlang_repo = https://github.com/ngerakines/erlang_twitter +pkg_twitter_erlang_commit = master + +PACKAGES += ucol_nif +pkg_ucol_nif_name = ucol_nif +pkg_ucol_nif_description = ICU based collation Erlang module +pkg_ucol_nif_homepage = https://github.com/refuge/ucol_nif +pkg_ucol_nif_fetch = git +pkg_ucol_nif_repo = https://github.com/refuge/ucol_nif +pkg_ucol_nif_commit = master + +PACKAGES += unicorn +pkg_unicorn_name = unicorn +pkg_unicorn_description = Generic configuration server +pkg_unicorn_homepage = https://github.com/shizzard/unicorn +pkg_unicorn_fetch = git +pkg_unicorn_repo = https://github.com/shizzard/unicorn +pkg_unicorn_commit = master + +PACKAGES += unsplit +pkg_unsplit_name = unsplit +pkg_unsplit_description = Resolves conflicts in Mnesia after network splits +pkg_unsplit_homepage = https://github.com/uwiger/unsplit +pkg_unsplit_fetch = git +pkg_unsplit_repo = https://github.com/uwiger/unsplit +pkg_unsplit_commit = master + +PACKAGES += uuid +pkg_uuid_name = uuid +pkg_uuid_description = Erlang UUID Implementation +pkg_uuid_homepage = https://github.com/okeuday/uuid +pkg_uuid_fetch = git +pkg_uuid_repo = https://github.com/okeuday/uuid +pkg_uuid_commit = master + +PACKAGES += ux +pkg_ux_name = ux +pkg_ux_description = Unicode eXtention for Erlang (Strings, Collation) +pkg_ux_homepage = https://github.com/erlang-unicode/ux +pkg_ux_fetch = git +pkg_ux_repo = https://github.com/erlang-unicode/ux +pkg_ux_commit = master + +PACKAGES += vert +pkg_vert_name = vert +pkg_vert_description = Erlang binding to libvirt virtualization API +pkg_vert_homepage = https://github.com/msantos/erlang-libvirt +pkg_vert_fetch = git +pkg_vert_repo = https://github.com/msantos/erlang-libvirt +pkg_vert_commit = master + +PACKAGES += verx +pkg_verx_name = verx +pkg_verx_description = Erlang implementation of the libvirtd remote protocol +pkg_verx_homepage = https://github.com/msantos/verx +pkg_verx_fetch = git +pkg_verx_repo = https://github.com/msantos/verx +pkg_verx_commit = master + +PACKAGES += vmq_acl +pkg_vmq_acl_name = vmq_acl +pkg_vmq_acl_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_acl_homepage = https://verne.mq/ +pkg_vmq_acl_fetch = git +pkg_vmq_acl_repo = https://github.com/erlio/vmq_acl +pkg_vmq_acl_commit = master + +PACKAGES += vmq_bridge +pkg_vmq_bridge_name = vmq_bridge +pkg_vmq_bridge_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_bridge_homepage = https://verne.mq/ +pkg_vmq_bridge_fetch = git +pkg_vmq_bridge_repo = https://github.com/erlio/vmq_bridge +pkg_vmq_bridge_commit = master + +PACKAGES += vmq_graphite +pkg_vmq_graphite_name = vmq_graphite +pkg_vmq_graphite_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_graphite_homepage = https://verne.mq/ +pkg_vmq_graphite_fetch = git +pkg_vmq_graphite_repo = https://github.com/erlio/vmq_graphite +pkg_vmq_graphite_commit = master + +PACKAGES += vmq_passwd +pkg_vmq_passwd_name = vmq_passwd +pkg_vmq_passwd_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_passwd_homepage = https://verne.mq/ +pkg_vmq_passwd_fetch = git +pkg_vmq_passwd_repo = https://github.com/erlio/vmq_passwd +pkg_vmq_passwd_commit = master + +PACKAGES += vmq_server +pkg_vmq_server_name = vmq_server +pkg_vmq_server_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_server_homepage = https://verne.mq/ +pkg_vmq_server_fetch = git +pkg_vmq_server_repo = https://github.com/erlio/vmq_server +pkg_vmq_server_commit = master + +PACKAGES += vmq_snmp +pkg_vmq_snmp_name = vmq_snmp +pkg_vmq_snmp_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_snmp_homepage = https://verne.mq/ +pkg_vmq_snmp_fetch = git +pkg_vmq_snmp_repo = https://github.com/erlio/vmq_snmp +pkg_vmq_snmp_commit = master + +PACKAGES += vmq_systree +pkg_vmq_systree_name = vmq_systree +pkg_vmq_systree_description = Component of VerneMQ: A distributed MQTT message broker +pkg_vmq_systree_homepage = https://verne.mq/ +pkg_vmq_systree_fetch = git +pkg_vmq_systree_repo = https://github.com/erlio/vmq_systree +pkg_vmq_systree_commit = master + +PACKAGES += vmstats +pkg_vmstats_name = vmstats +pkg_vmstats_description = tiny Erlang app that works in conjunction with statsderl in order to generate information on the Erlang VM for graphite logs. +pkg_vmstats_homepage = https://github.com/ferd/vmstats +pkg_vmstats_fetch = git +pkg_vmstats_repo = https://github.com/ferd/vmstats +pkg_vmstats_commit = master + +PACKAGES += walrus +pkg_walrus_name = walrus +pkg_walrus_description = Walrus - Mustache-like Templating +pkg_walrus_homepage = https://github.com/devinus/walrus +pkg_walrus_fetch = git +pkg_walrus_repo = https://github.com/devinus/walrus +pkg_walrus_commit = master + +PACKAGES += webmachine +pkg_webmachine_name = webmachine +pkg_webmachine_description = A REST-based system for building web applications. +pkg_webmachine_homepage = https://github.com/basho/webmachine +pkg_webmachine_fetch = git +pkg_webmachine_repo = https://github.com/basho/webmachine +pkg_webmachine_commit = master + +PACKAGES += websocket_client +pkg_websocket_client_name = websocket_client +pkg_websocket_client_description = Erlang websocket client (ws and wss supported) +pkg_websocket_client_homepage = https://github.com/jeremyong/websocket_client +pkg_websocket_client_fetch = git +pkg_websocket_client_repo = https://github.com/jeremyong/websocket_client +pkg_websocket_client_commit = master + +PACKAGES += worker_pool +pkg_worker_pool_name = worker_pool +pkg_worker_pool_description = a simple erlang worker pool +pkg_worker_pool_homepage = https://github.com/inaka/worker_pool +pkg_worker_pool_fetch = git +pkg_worker_pool_repo = https://github.com/inaka/worker_pool +pkg_worker_pool_commit = master + +PACKAGES += wrangler +pkg_wrangler_name = wrangler +pkg_wrangler_description = Import of the Wrangler svn repository. +pkg_wrangler_homepage = http://www.cs.kent.ac.uk/projects/wrangler/Home.html +pkg_wrangler_fetch = git +pkg_wrangler_repo = https://github.com/RefactoringTools/wrangler +pkg_wrangler_commit = master + +PACKAGES += wsock +pkg_wsock_name = wsock +pkg_wsock_description = Erlang library to build WebSocket clients and servers +pkg_wsock_homepage = https://github.com/madtrick/wsock +pkg_wsock_fetch = git +pkg_wsock_repo = https://github.com/madtrick/wsock +pkg_wsock_commit = master + +PACKAGES += xhttpc +pkg_xhttpc_name = xhttpc +pkg_xhttpc_description = Extensible HTTP Client for Erlang +pkg_xhttpc_homepage = https://github.com/seriyps/xhttpc +pkg_xhttpc_fetch = git +pkg_xhttpc_repo = https://github.com/seriyps/xhttpc +pkg_xhttpc_commit = master + +PACKAGES += xref_runner +pkg_xref_runner_name = xref_runner +pkg_xref_runner_description = Erlang Xref Runner (inspired in rebar xref) +pkg_xref_runner_homepage = https://github.com/inaka/xref_runner +pkg_xref_runner_fetch = git +pkg_xref_runner_repo = https://github.com/inaka/xref_runner +pkg_xref_runner_commit = master + +PACKAGES += yamerl +pkg_yamerl_name = yamerl +pkg_yamerl_description = YAML 1.2 parser in pure Erlang +pkg_yamerl_homepage = https://github.com/yakaz/yamerl +pkg_yamerl_fetch = git +pkg_yamerl_repo = https://github.com/yakaz/yamerl +pkg_yamerl_commit = master + +PACKAGES += yamler +pkg_yamler_name = yamler +pkg_yamler_description = libyaml-based yaml loader for Erlang +pkg_yamler_homepage = https://github.com/goertzenator/yamler +pkg_yamler_fetch = git +pkg_yamler_repo = https://github.com/goertzenator/yamler +pkg_yamler_commit = master + +PACKAGES += yaws +pkg_yaws_name = yaws +pkg_yaws_description = Yaws webserver +pkg_yaws_homepage = http://yaws.hyber.org +pkg_yaws_fetch = git +pkg_yaws_repo = https://github.com/klacke/yaws +pkg_yaws_commit = master + +PACKAGES += zab_engine +pkg_zab_engine_name = zab_engine +pkg_zab_engine_description = zab propotocol implement by erlang +pkg_zab_engine_homepage = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_fetch = git +pkg_zab_engine_repo = https://github.com/xinmingyao/zab_engine +pkg_zab_engine_commit = master + +PACKAGES += zabbix_sender +pkg_zabbix_sender_name = zabbix_sender +pkg_zabbix_sender_description = Zabbix trapper for sending data to Zabbix in pure Erlang +pkg_zabbix_sender_homepage = https://github.com/stalkermn/zabbix_sender +pkg_zabbix_sender_fetch = git +pkg_zabbix_sender_repo = https://github.com/stalkermn/zabbix_sender.git +pkg_zabbix_sender_commit = master + +PACKAGES += zeta +pkg_zeta_name = zeta +pkg_zeta_description = HTTP access log parser in Erlang +pkg_zeta_homepage = https://github.com/s1n4/zeta +pkg_zeta_fetch = git +pkg_zeta_repo = https://github.com/s1n4/zeta +pkg_zeta_commit = master + +PACKAGES += zippers +pkg_zippers_name = zippers +pkg_zippers_description = A library for functional zipper data structures in Erlang. Read more on zippers +pkg_zippers_homepage = https://github.com/ferd/zippers +pkg_zippers_fetch = git +pkg_zippers_repo = https://github.com/ferd/zippers +pkg_zippers_commit = master + +PACKAGES += zlists +pkg_zlists_name = zlists +pkg_zlists_description = Erlang lazy lists library. +pkg_zlists_homepage = https://github.com/vjache/erlang-zlists +pkg_zlists_fetch = git +pkg_zlists_repo = https://github.com/vjache/erlang-zlists +pkg_zlists_commit = master + +PACKAGES += zraft_lib +pkg_zraft_lib_name = zraft_lib +pkg_zraft_lib_description = Erlang raft consensus protocol implementation +pkg_zraft_lib_homepage = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_fetch = git +pkg_zraft_lib_repo = https://github.com/dreyk/zraft_lib +pkg_zraft_lib_commit = master + +PACKAGES += zucchini +pkg_zucchini_name = zucchini +pkg_zucchini_description = An Erlang INI parser +pkg_zucchini_homepage = https://github.com/devinus/zucchini +pkg_zucchini_fetch = git +pkg_zucchini_repo = https://github.com/devinus/zucchini +pkg_zucchini_commit = master + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: search + +define pkg_print + $(verbose) printf "%s\n" \ + $(if $(call core_eq,$(1),$(pkg_$(1)_name)),,"Pkg name: $(1)") \ + "App name: $(pkg_$(1)_name)" \ + "Description: $(pkg_$(1)_description)" \ + "Home page: $(pkg_$(1)_homepage)" \ + "Fetch with: $(pkg_$(1)_fetch)" \ + "Repository: $(pkg_$(1)_repo)" \ + "Commit: $(pkg_$(1)_commit)" \ + "" + +endef + +search: +ifdef q + $(foreach p,$(PACKAGES), \ + $(if $(findstring $(call core_lc,$(q)),$(call core_lc,$(pkg_$(p)_name) $(pkg_$(p)_description))), \ + $(call pkg_print,$(p)))) +else + $(foreach p,$(PACKAGES),$(call pkg_print,$(p))) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-deps + +# Configuration. + +ifdef OTP_DEPS +$(warning The variable OTP_DEPS is deprecated in favor of LOCAL_DEPS.) +endif + +IGNORE_DEPS ?= +export IGNORE_DEPS + +APPS_DIR ?= $(CURDIR)/apps +export APPS_DIR + +DEPS_DIR ?= $(CURDIR)/deps +export DEPS_DIR + +REBAR_DEPS_DIR = $(DEPS_DIR) +export REBAR_DEPS_DIR + +dep_name = $(if $(dep_$(1)),$(1),$(if $(pkg_$(1)_name),$(pkg_$(1)_name),$(1))) +dep_repo = $(patsubst git://github.com/%,https://github.com/%, \ + $(if $(dep_$(1)),$(word 2,$(dep_$(1))),$(pkg_$(1)_repo))) +dep_commit = $(if $(dep_$(1)_commit),$(dep_$(1)_commit),$(if $(dep_$(1)),$(word 3,$(dep_$(1))),$(pkg_$(1)_commit))) + +ALL_APPS_DIRS = $(if $(wildcard $(APPS_DIR)/),$(filter-out $(APPS_DIR),$(shell find $(APPS_DIR) -maxdepth 1 -type d))) +ALL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(foreach dep,$(filter-out $(IGNORE_DEPS),$(BUILD_DEPS) $(DEPS)),$(call dep_name,$(dep)))) + +ifeq ($(filter $(APPS_DIR) $(DEPS_DIR),$(subst :, ,$(ERL_LIBS))),) +ifeq ($(ERL_LIBS),) + ERL_LIBS = $(APPS_DIR):$(DEPS_DIR) +else + ERL_LIBS := $(ERL_LIBS):$(APPS_DIR):$(DEPS_DIR) +endif +endif +export ERL_LIBS + +export NO_AUTOPATCH + +# Verbosity. + +dep_verbose_0 = @echo " DEP " $(1); +dep_verbose_2 = set -x; +dep_verbose = $(dep_verbose_$(V)) + +# Core targets. + +ifdef IS_APP +apps:: +else +apps:: $(ALL_APPS_DIRS) +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/apps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) +# Create ebin directory for all apps to make sure Erlang recognizes them +# as proper OTP applications when using -include_lib. This is a temporary +# fix, a proper fix would be to compile apps/* in the right order. + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + mkdir -p $$dep/ebin || exit $$?; \ + done + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/apps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/apps.log; \ + $(MAKE) -C $$dep IS_APP=1 || exit $$?; \ + fi \ + done +endif + +ifneq ($(SKIP_DEPS),) +deps:: +else +deps:: $(ALL_DEPS_DIRS) apps +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) rm -f $(ERLANG_MK_TMP)/deps.log +endif + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) for dep in $(ALL_DEPS_DIRS) ; do \ + if grep -qs ^$$dep$$ $(ERLANG_MK_TMP)/deps.log; then \ + :; \ + else \ + echo $$dep >> $(ERLANG_MK_TMP)/deps.log; \ + if [ -f $$dep/GNUmakefile ] || [ -f $$dep/makefile ] || [ -f $$dep/Makefile ]; then \ + $(MAKE) -C $$dep IS_DEP=1 || exit $$?; \ + else \ + echo "Error: No Makefile to build dependency $$dep."; \ + exit 2; \ + fi \ + fi \ + done +endif + +# Deps related targets. + +# @todo rename GNUmakefile and makefile into Makefile first, if they exist +# While Makefile file could be GNUmakefile or makefile, +# in practice only Makefile is needed so far. +define dep_autopatch + if [ -f $(DEPS_DIR)/$(1)/erlang.mk ]; then \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + $(call dep_autopatch_erlang_mk,$(1)); \ + elif [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + if [ 0 != `grep -c "include ../\w*\.mk" $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ 0 != `grep -ci rebar $(DEPS_DIR)/$(1)/Makefile` ]; then \ + $(call dep_autopatch2,$(1)); \ + elif [ -n "`find $(DEPS_DIR)/$(1)/ -type f -name \*.mk -not -name erlang.mk -exec grep -i rebar '{}' \;`" ]; then \ + $(call dep_autopatch2,$(1)); \ + else \ + $(call erlang,$(call dep_autopatch_app.erl,$(1))); \ + fi \ + else \ + if [ ! -d $(DEPS_DIR)/$(1)/src/ ]; then \ + $(call dep_autopatch_noop,$(1)); \ + else \ + $(call dep_autopatch2,$(1)); \ + fi \ + fi +endef + +define dep_autopatch2 + if [ -f $(DEPS_DIR)/$1/src/$1.app.src.script ]; then \ + $(call erlang,$(call dep_autopatch_appsrc_script.erl,$(1))); \ + fi; \ + $(call erlang,$(call dep_autopatch_appsrc.erl,$(1))); \ + if [ -f $(DEPS_DIR)/$(1)/rebar -o -f $(DEPS_DIR)/$(1)/rebar.config -o -f $(DEPS_DIR)/$(1)/rebar.config.script ]; then \ + $(call dep_autopatch_fetch_rebar); \ + $(call dep_autopatch_rebar,$(1)); \ + else \ + $(call dep_autopatch_gen,$(1)); \ + fi +endef + +define dep_autopatch_noop + printf "noop:\n" > $(DEPS_DIR)/$(1)/Makefile +endef + +# Overwrite erlang.mk with the current file by default. +ifeq ($(NO_AUTOPATCH_ERLANG_MK),) +define dep_autopatch_erlang_mk + echo "include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk" \ + > $(DEPS_DIR)/$1/erlang.mk +endef +else +define dep_autopatch_erlang_mk + : +endef +endif + +define dep_autopatch_gen + printf "%s\n" \ + "ERLC_OPTS = +debug_info" \ + "include ../../erlang.mk" > $(DEPS_DIR)/$(1)/Makefile +endef + +define dep_autopatch_fetch_rebar + mkdir -p $(ERLANG_MK_TMP); \ + if [ ! -d $(ERLANG_MK_TMP)/rebar ]; then \ + git clone -q -n -- https://github.com/rebar/rebar $(ERLANG_MK_TMP)/rebar; \ + cd $(ERLANG_MK_TMP)/rebar; \ + git checkout -q 791db716b5a3a7671e0b351f95ddf24b848ee173; \ + $(MAKE); \ + cd -; \ + fi +endef + +define dep_autopatch_rebar + if [ -f $(DEPS_DIR)/$(1)/Makefile ]; then \ + mv $(DEPS_DIR)/$(1)/Makefile $(DEPS_DIR)/$(1)/Makefile.orig.mk; \ + fi; \ + $(call erlang,$(call dep_autopatch_rebar.erl,$(1))); \ + rm -f $(DEPS_DIR)/$(1)/ebin/$(1).app +endef + +define dep_autopatch_rebar.erl + application:load(rebar), + application:set_env(rebar, log_level, debug), + Conf1 = case file:consult("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config)") of + {ok, Conf0} -> Conf0; + _ -> [] + end, + {Conf, OsEnv} = fun() -> + case filelib:is_file("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)") of + false -> {Conf1, []}; + true -> + Bindings0 = erl_eval:new_bindings(), + Bindings1 = erl_eval:add_binding('CONFIG', Conf1, Bindings0), + Bindings = erl_eval:add_binding('SCRIPT', "$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings1), + Before = os:getenv(), + {ok, Conf2} = file:script("$(call core_native_path,$(DEPS_DIR)/$1/rebar.config.script)", Bindings), + {Conf2, lists:foldl(fun(E, Acc) -> lists:delete(E, Acc) end, os:getenv(), Before)} + end + end(), + Write = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/Makefile)", Text, [append]) + end, + Escape = fun (Text) -> + re:replace(Text, "\\\\$$", "\$$$$", [global, {return, list}]) + end, + Write("IGNORE_DEPS += edown eper eunit_formatters meck node_package " + "rebar_lock_deps_plugin rebar_vsn_plugin reltool_util\n"), + Write("C_SRC_DIR = /path/do/not/exist\n"), + Write("C_SRC_TYPE = rebar\n"), + Write("DRV_CFLAGS = -fPIC\nexport DRV_CFLAGS\n"), + Write(["ERLANG_ARCH = ", rebar_utils:wordsize(), "\nexport ERLANG_ARCH\n"]), + fun() -> + Write("ERLC_OPTS = +debug_info\nexport ERLC_OPTS\n"), + case lists:keyfind(erl_opts, 1, Conf) of + false -> ok; + {_, ErlOpts} -> + lists:foreach(fun + ({d, D}) -> + Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + ({i, I}) -> + Write(["ERLC_OPTS += -I ", I, "\n"]); + ({platform_define, Regex, D}) -> + case rebar_utils:is_arch(Regex) of + true -> Write("ERLC_OPTS += -D" ++ atom_to_list(D) ++ "=1\n"); + false -> ok + end; + ({parse_transform, PT}) -> + Write("ERLC_OPTS += +'{parse_transform, " ++ atom_to_list(PT) ++ "}'\n"); + (_) -> ok + end, ErlOpts) + end, + Write("\n") + end(), + fun() -> + File = case lists:keyfind(deps, 1, Conf) of + false -> []; + {_, Deps} -> + [begin case case Dep of + {N, S} when is_atom(N), is_list(S) -> {N, {hex, S}}; + {N, S} when is_tuple(S) -> {N, S}; + {N, _, S} -> {N, S}; + {N, _, S, _} -> {N, S}; + _ -> false + end of + false -> ok; + {Name, Source} -> + {Method, Repo, Commit} = case Source of + {hex, V} -> {hex, V, undefined}; + {git, R} -> {git, R, master}; + {M, R, {branch, C}} -> {M, R, C}; + {M, R, {ref, C}} -> {M, R, C}; + {M, R, {tag, C}} -> {M, R, C}; + {M, R, C} -> {M, R, C} + end, + Write(io_lib:format("DEPS += ~s\ndep_~s = ~s ~s ~s~n", [Name, Name, Method, Repo, Commit])) + end end || Dep <- Deps] + end + end(), + fun() -> + case lists:keyfind(erl_first_files, 1, Conf) of + false -> ok; + {_, Files} -> + Names = [[" ", case lists:reverse(F) of + "lre." ++ Elif -> lists:reverse(Elif); + Elif -> lists:reverse(Elif) + end] || "src/" ++ F <- Files], + Write(io_lib:format("COMPILE_FIRST +=~s\n", [Names])) + end + end(), + Write("\n\nrebar_dep: preprocess pre-deps deps pre-app app\n"), + Write("\npreprocess::\n"), + Write("\npre-deps::\n"), + Write("\npre-app::\n"), + PatchHook = fun(Cmd) -> + case Cmd of + "make -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "gmake -C" ++ Cmd1 -> "$$\(MAKE) -C" ++ Escape(Cmd1); + "make " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + "gmake " ++ Cmd1 -> "$$\(MAKE) -f Makefile.orig.mk " ++ Escape(Cmd1); + _ -> Escape(Cmd) + end + end, + fun() -> + case lists:keyfind(pre_hooks, 1, Conf) of + false -> ok; + {_, Hooks} -> + [case H of + {'get-deps', Cmd} -> + Write("\npre-deps::\n\t" ++ PatchHook(Cmd) ++ "\n"); + {compile, Cmd} -> + Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + {Regex, compile, Cmd} -> + case rebar_utils:is_arch(Regex) of + true -> Write("\npre-app::\n\tCC=$$\(CC) " ++ PatchHook(Cmd) ++ "\n"); + false -> ok + end; + _ -> ok + end || H <- Hooks] + end + end(), + ShellToMk = fun(V) -> + re:replace(re:replace(V, "(\\\\$$)(\\\\w*)", "\\\\1(\\\\2)", [global]), + "-Werror\\\\b", "", [{return, list}, global]) + end, + PortSpecs = fun() -> + case lists:keyfind(port_specs, 1, Conf) of + false -> + case filelib:is_dir("$(call core_native_path,$(DEPS_DIR)/$1/c_src)") of + false -> []; + true -> + [{"priv/" ++ proplists:get_value(so_name, Conf, "$(1)_drv.so"), + proplists:get_value(port_sources, Conf, ["c_src/*.c"]), []}] + end; + {_, Specs} -> + lists:flatten([case S of + {Output, Input} -> {ShellToMk(Output), Input, []}; + {Regex, Output, Input} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, []}; + false -> [] + end; + {Regex, Output, Input, [{env, Env}]} -> + case rebar_utils:is_arch(Regex) of + true -> {ShellToMk(Output), Input, Env}; + false -> [] + end + end || S <- Specs]) + end + end(), + PortSpecWrite = fun (Text) -> + file:write_file("$(call core_native_path,$(DEPS_DIR)/$1/c_src/Makefile.erlang.mk)", Text, [append]) + end, + case PortSpecs of + [] -> ok; + _ -> + Write("\npre-app::\n\t$$\(MAKE) -f c_src/Makefile.erlang.mk\n"), + PortSpecWrite(io_lib:format("ERL_CFLAGS = -finline-functions -Wall -fPIC -I \\"~s/erts-~s/include\\" -I \\"~s\\"\n", + [code:root_dir(), erlang:system_info(version), code:lib_dir(erl_interface, include)])), + PortSpecWrite(io_lib:format("ERL_LDFLAGS = -L \\"~s\\" -lerl_interface -lei\n", + [code:lib_dir(erl_interface, lib)])), + [PortSpecWrite(["\n", E, "\n"]) || E <- OsEnv], + FilterEnv = fun(Env) -> + lists:flatten([case E of + {_, _} -> E; + {Regex, K, V} -> + case rebar_utils:is_arch(Regex) of + true -> {K, V}; + false -> [] + end + end || E <- Env]) + end, + MergeEnv = fun(Env) -> + lists:foldl(fun ({K, V}, Acc) -> + case lists:keyfind(K, 1, Acc) of + false -> [{K, rebar_utils:expand_env_variable(V, K, "")}|Acc]; + {_, V0} -> [{K, rebar_utils:expand_env_variable(V, K, V0)}|Acc] + end + end, [], Env) + end, + PortEnv = case lists:keyfind(port_env, 1, Conf) of + false -> []; + {_, PortEnv0} -> FilterEnv(PortEnv0) + end, + PortSpec = fun ({Output, Input0, Env}) -> + filelib:ensure_dir("$(call core_native_path,$(DEPS_DIR)/$1/)" ++ Output), + Input = [[" ", I] || I <- Input0], + PortSpecWrite([ + [["\n", K, " = ", ShellToMk(V)] || {K, V} <- lists:reverse(MergeEnv(PortEnv))], + case $(PLATFORM) of + darwin -> "\n\nLDFLAGS += -flat_namespace -undefined suppress"; + _ -> "" + end, + "\n\nall:: ", Output, "\n\n", + "%.o: %.c\n\t$$\(CC) -c -o $$\@ $$\< $$\(CFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.C\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cc\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + "%.o: %.cpp\n\t$$\(CXX) -c -o $$\@ $$\< $$\(CXXFLAGS) $$\(ERL_CFLAGS) $$\(DRV_CFLAGS) $$\(EXE_CFLAGS)\n\n", + [[Output, ": ", K, " = ", ShellToMk(V), "\n"] || {K, V} <- lists:reverse(MergeEnv(FilterEnv(Env)))], + Output, ": $$\(foreach ext,.c .C .cc .cpp,", + "$$\(patsubst %$$\(ext),%.o,$$\(filter %$$\(ext),$$\(wildcard", Input, "))))\n", + "\t$$\(CC) -o $$\@ $$\? $$\(LDFLAGS) $$\(ERL_LDFLAGS) $$\(DRV_LDFLAGS) $$\(EXE_LDFLAGS)", + case {filename:extension(Output), $(PLATFORM)} of + {[], _} -> "\n"; + {_, darwin} -> "\n"; + _ -> " -shared\n" + end]) + end, + [PortSpec(S) || S <- PortSpecs] + end, + Write("\ninclude $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(DEPS_DIR)/app)/erlang.mk"), + RunPlugin = fun(Plugin, Step) -> + case erlang:function_exported(Plugin, Step, 2) of + false -> ok; + true -> + c:cd("$(call core_native_path,$(DEPS_DIR)/$1/)"), + Ret = Plugin:Step({config, "", Conf, dict:new(), dict:new(), dict:new(), + dict:store(base_dir, "", dict:new())}, undefined), + io:format("rebar plugin ~p step ~p ret ~p~n", [Plugin, Step, Ret]) + end + end, + fun() -> + case lists:keyfind(plugins, 1, Conf) of + false -> ok; + {_, Plugins} -> + [begin + case lists:keyfind(deps, 1, Conf) of + false -> ok; + {_, Deps} -> + case lists:keyfind(P, 1, Deps) of + false -> ok; + _ -> + Path = "$(call core_native_path,$(DEPS_DIR)/)" ++ atom_to_list(P), + io:format("~s", [os:cmd("$(MAKE) -C $(call core_native_path,$(DEPS_DIR)/$1) " ++ Path)]), + io:format("~s", [os:cmd("$(MAKE) -C " ++ Path ++ " IS_DEP=1")]), + code:add_patha(Path ++ "/ebin") + end + end + end || P <- Plugins], + [case code:load_file(P) of + {module, P} -> ok; + _ -> + case lists:keyfind(plugin_dir, 1, Conf) of + false -> ok; + {_, PluginsDir} -> + ErlFile = "$(call core_native_path,$(DEPS_DIR)/$1/)" ++ PluginsDir ++ "/" ++ atom_to_list(P) ++ ".erl", + {ok, P, Bin} = compile:file(ErlFile, [binary]), + {module, P} = code:load_binary(P, ErlFile, Bin) + end + end || P <- Plugins], + [RunPlugin(P, preprocess) || P <- Plugins], + [RunPlugin(P, pre_compile) || P <- Plugins], + [RunPlugin(P, compile) || P <- Plugins] + end + end(), + halt() +endef + +define dep_autopatch_app.erl + UpdateModules = fun(App) -> + case filelib:is_regular(App) of + false -> ok; + true -> + {ok, [{application, '$(1)', L0}]} = file:consult(App), + Mods = filelib:fold_files("$(call core_native_path,$(DEPS_DIR)/$1/src)", "\\\\.erl$$", true, + fun (F, Acc) -> [list_to_atom(filename:rootname(filename:basename(F)))|Acc] end, []), + L = lists:keystore(modules, 1, L0, {modules, Mods}), + ok = file:write_file(App, io_lib:format("~p.~n", [{application, '$(1)', L}])) + end + end, + UpdateModules("$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"), + halt() +endef + +define dep_autopatch_appsrc_script.erl + AppSrc = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcScript = AppSrc ++ ".script", + Bindings = erl_eval:new_bindings(), + {ok, Conf} = file:script(AppSrcScript, Bindings), + ok = file:write_file(AppSrc, io_lib:format("~p.~n", [Conf])), + halt() +endef + +define dep_autopatch_appsrc.erl + AppSrcOut = "$(call core_native_path,$(DEPS_DIR)/$1/src/$1.app.src)", + AppSrcIn = case filelib:is_regular(AppSrcOut) of false -> "$(call core_native_path,$(DEPS_DIR)/$1/ebin/$1.app)"; true -> AppSrcOut end, + case filelib:is_regular(AppSrcIn) of + false -> ok; + true -> + {ok, [{application, $(1), L0}]} = file:consult(AppSrcIn), + L1 = lists:keystore(modules, 1, L0, {modules, []}), + L2 = case lists:keyfind(vsn, 1, L1) of {_, git} -> lists:keyreplace(vsn, 1, L1, {vsn, "git"}); _ -> L1 end, + L3 = case lists:keyfind(registered, 1, L2) of false -> [{registered, []}|L2]; _ -> L2 end, + ok = file:write_file(AppSrcOut, io_lib:format("~p.~n", [{application, $(1), L3}])), + case AppSrcOut of AppSrcIn -> ok; _ -> ok = file:delete(AppSrcIn) end + end, + halt() +endef + +define dep_fetch_git + git clone -q -n -- $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && git checkout -q $(call dep_commit,$(1)); +endef + +define dep_fetch_git-submodule + git submodule update --init -- $(DEPS_DIR)/$1; +endef + +define dep_fetch_hg + hg clone -q -U $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && hg update -q $(call dep_commit,$(1)); +endef + +define dep_fetch_svn + svn checkout -q $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_cp + cp -R $(call dep_repo,$(1)) $(DEPS_DIR)/$(call dep_name,$(1)); +endef + +define dep_fetch_hex.erl + ssl:start(), + inets:start(), + {ok, {{_, 200, _}, _, Body}} = httpc:request(get, + {"https://s3.amazonaws.com/s3.hex.pm/tarballs/$(1)-$(2).tar", []}, + [], [{body_format, binary}]), + {ok, Files} = erl_tar:extract({binary, Body}, [memory]), + {_, Source} = lists:keyfind("contents.tar.gz", 1, Files), + ok = erl_tar:extract({binary, Source}, [{cwd, "$(call core_native_path,$(DEPS_DIR)/$1)"}, compressed]), + halt() +endef + +# Hex only has a package version. No need to look in the Erlang.mk packages. +define dep_fetch_hex + $(call erlang,$(call dep_fetch_hex.erl,$(1),$(strip $(word 2,$(dep_$(1)))))); +endef + +define dep_fetch_fail + echo "Error: Unknown or invalid dependency: $(1)." >&2; \ + exit 78; +endef + +# Kept for compatibility purposes with older Erlang.mk configuration. +define dep_fetch_legacy + $(warning WARNING: '$(1)' dependency configuration uses deprecated format.) \ + git clone -q -n -- $(word 1,$(dep_$(1))) $(DEPS_DIR)/$(1); \ + cd $(DEPS_DIR)/$(1) && git checkout -q $(if $(word 2,$(dep_$(1))),$(word 2,$(dep_$(1))),master); +endef + +define dep_fetch + $(if $(dep_$(1)), \ + $(if $(dep_fetch_$(word 1,$(dep_$(1)))), \ + $(word 1,$(dep_$(1))), \ + $(if $(IS_DEP),legacy,fail)), \ + $(if $(filter $(1),$(PACKAGES)), \ + $(pkg_$(1)_fetch), \ + fail)) +endef + +define dep_target +$(DEPS_DIR)/$(call dep_name,$1): + $(eval DEP_NAME := $(call dep_name,$1)) + $(eval DEP_STR := $(if $(filter-out $1,$(DEP_NAME)),$1,"$1 ($(DEP_NAME))")) + $(verbose) if test -d $(APPS_DIR)/$(DEP_NAME); then \ + echo "Error: Dependency" $(DEP_STR) "conflicts with application found in $(APPS_DIR)/$(DEP_NAME)."; \ + exit 17; \ + fi + $(verbose) mkdir -p $(DEPS_DIR) + $(dep_verbose) $(call dep_fetch_$(strip $(call dep_fetch,$(1))),$(1)) + $(verbose) if [ -f $(DEPS_DIR)/$(1)/configure.ac -o -f $(DEPS_DIR)/$(1)/configure.in ] \ + && [ ! -f $(DEPS_DIR)/$(1)/configure ]; then \ + echo " AUTO " $(1); \ + cd $(DEPS_DIR)/$(1) && autoreconf -Wall -vif -I m4; \ + fi + - $(verbose) if [ -f $(DEPS_DIR)/$(DEP_NAME)/configure ]; then \ + echo " CONF " $(DEP_STR); \ + cd $(DEPS_DIR)/$(DEP_NAME) && ./configure; \ + fi +ifeq ($(filter $(1),$(NO_AUTOPATCH)),) + $(verbose) if [ "$(1)" = "amqp_client" -a "$(RABBITMQ_CLIENT_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi; \ + if [ ! -d $(DEPS_DIR)/rabbitmq-server ]; then \ + echo " PATCH Downloading rabbitmq-server"; \ + git clone https://github.com/rabbitmq/rabbitmq-server.git $(DEPS_DIR)/rabbitmq-server; \ + fi; \ + ln -s $(DEPS_DIR)/amqp_client/deps/rabbit_common-0.0.0 $(DEPS_DIR)/rabbit_common; \ + elif [ "$(1)" = "rabbit" -a "$(RABBITMQ_SERVER_PATCH)" ]; then \ + if [ ! -d $(DEPS_DIR)/rabbitmq-codegen ]; then \ + echo " PATCH Downloading rabbitmq-codegen"; \ + git clone https://github.com/rabbitmq/rabbitmq-codegen.git $(DEPS_DIR)/rabbitmq-codegen; \ + fi \ + else \ + $$(call dep_autopatch,$(DEP_NAME)) \ + fi +endif +endef + +$(foreach dep,$(BUILD_DEPS) $(DEPS),$(eval $(call dep_target,$(dep)))) + +ifndef IS_APP +clean:: clean-apps + +clean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep clean IS_APP=1 || exit $$?; \ + done + +distclean:: distclean-apps + +distclean-apps: + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep distclean IS_APP=1 || exit $$?; \ + done +endif + +ifndef SKIP_DEPS +distclean:: distclean-deps + +distclean-deps: + $(gen_verbose) rm -rf $(DEPS_DIR) +endif + +# Forward-declare variables used in core/deps-tools.mk. This is required +# in case plugins use them. + +ERLANG_MK_RECURSIVE_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-deps-list.log +ERLANG_MK_RECURSIVE_DOC_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-doc-deps-list.log +ERLANG_MK_RECURSIVE_REL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-rel-deps-list.log +ERLANG_MK_RECURSIVE_TEST_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-test-deps-list.log +ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST = $(ERLANG_MK_TMP)/recursive-shell-deps-list.log + +# External plugins. + +DEP_PLUGINS ?= + +define core_dep_plugin +-include $(DEPS_DIR)/$(1) + +$(DEPS_DIR)/$(1): $(DEPS_DIR)/$(2) ; +endef + +$(foreach p,$(DEP_PLUGINS),\ + $(eval $(if $(findstring /,$p),\ + $(call core_dep_plugin,$p,$(firstword $(subst /, ,$p))),\ + $(call core_dep_plugin,$p/plugins.mk,$p)))) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Configuration. + +DTL_FULL_PATH ?= +DTL_PATH ?= templates/ +DTL_SUFFIX ?= _dtl +DTL_OPTS ?= + +# Verbosity. + +dtl_verbose_0 = @echo " DTL " $(filter %.dtl,$(?F)); +dtl_verbose = $(dtl_verbose_$(V)) + +# Core targets. + +DTL_FILES = $(sort $(call core_find,$(DTL_PATH),*.dtl)) + +ifneq ($(DTL_FILES),) + +ifdef DTL_FULL_PATH +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(subst /,_,$(DTL_FILES:$(DTL_PATH)%=%)))) +else +BEAM_FILES += $(addprefix ebin/,$(patsubst %.dtl,%_dtl.beam,$(notdir $(DTL_FILES)))) +endif + +ifneq ($(words $(DTL_FILES)),0) +# Rebuild templates when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change-erlydtl: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(DTL_FILES); \ + fi + @touch $@ + +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change-erlydtl +endif + +define erlydtl_compile.erl + [begin + Module0 = case "$(strip $(DTL_FULL_PATH))" of + "" -> + filename:basename(F, ".dtl"); + _ -> + "$(DTL_PATH)" ++ F2 = filename:rootname(F, ".dtl"), + re:replace(F2, "/", "_", [{return, list}, global]) + end, + Module = list_to_atom(string:to_lower(Module0) ++ "$(DTL_SUFFIX)"), + case erlydtl:compile(F, Module, [$(DTL_OPTS)] ++ [{out_dir, "ebin/"}, return_errors, {doc_root, "templates"}]) of + ok -> ok; + {ok, _} -> ok + end + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ebin/$(PROJECT).app:: $(DTL_FILES) | ebin/ + $(if $(strip $?),\ + $(dtl_verbose) $(call erlang,$(call erlydtl_compile.erl,$?),-pa ebin/ $(DEPS_DIR)/erlydtl/ebin/)) + +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Verbosity. + +proto_verbose_0 = @echo " PROTO " $(filter %.proto,$(?F)); +proto_verbose = $(proto_verbose_$(V)) + +# Core targets. + +define compile_proto + $(verbose) mkdir -p ebin/ include/ + $(proto_verbose) $(call erlang,$(call compile_proto.erl,$(1))) + $(proto_verbose) erlc +debug_info -o ebin/ ebin/*.erl + $(verbose) rm ebin/*.erl +endef + +define compile_proto.erl + [begin + Dir = filename:dirname(filename:dirname(F)), + protobuffs_compile:generate_source(F, + [{output_include_dir, Dir ++ "/include"}, + {output_src_dir, Dir ++ "/ebin"}]) + end || F <- string:tokens("$(1)", " ")], + halt(). +endef + +ifneq ($(wildcard src/),) +ebin/$(PROJECT).app:: $(sort $(call core_find,src/,*.proto)) + $(if $(strip $?),$(call compile_proto,$?)) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-app + +# Configuration. + +ERLC_OPTS ?= -Werror +debug_info +warn_export_vars +warn_shadow_vars \ + +warn_obsolete_guard # +bin_opt_info +warn_export_all +warn_missing_spec +COMPILE_FIRST ?= +COMPILE_FIRST_PATHS = $(addprefix src/,$(addsuffix .erl,$(COMPILE_FIRST))) +ERLC_EXCLUDE ?= +ERLC_EXCLUDE_PATHS = $(addprefix src/,$(addsuffix .erl,$(ERLC_EXCLUDE))) + +ERLC_MIB_OPTS ?= +COMPILE_MIB_FIRST ?= +COMPILE_MIB_FIRST_PATHS = $(addprefix mibs/,$(addsuffix .mib,$(COMPILE_MIB_FIRST))) + +# Verbosity. + +app_verbose_0 = @echo " APP " $(PROJECT); +app_verbose_2 = set -x; +app_verbose = $(app_verbose_$(V)) + +appsrc_verbose_0 = @echo " APP " $(PROJECT).app.src; +appsrc_verbose_2 = set -x; +appsrc_verbose = $(appsrc_verbose_$(V)) + +makedep_verbose_0 = @echo " DEPEND" $(PROJECT).d; +makedep_verbose_2 = set -x; +makedep_verbose = $(makedep_verbose_$(V)) + +erlc_verbose_0 = @echo " ERLC " $(filter-out $(patsubst %,%.erl,$(ERLC_EXCLUDE)),\ + $(filter %.erl %.core,$(?F))); +erlc_verbose_2 = set -x; +erlc_verbose = $(erlc_verbose_$(V)) + +xyrl_verbose_0 = @echo " XYRL " $(filter %.xrl %.yrl,$(?F)); +xyrl_verbose_2 = set -x; +xyrl_verbose = $(xyrl_verbose_$(V)) + +asn1_verbose_0 = @echo " ASN1 " $(filter %.asn1,$(?F)); +asn1_verbose_2 = set -x; +asn1_verbose = $(asn1_verbose_$(V)) + +mib_verbose_0 = @echo " MIB " $(filter %.bin %.mib,$(?F)); +mib_verbose_2 = set -x; +mib_verbose = $(mib_verbose_$(V)) + +ifneq ($(wildcard src/),) + +# Targets. + +ifeq ($(wildcard ebin/test),) +app:: deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +else +app:: clean deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build +endif + +ifeq ($(wildcard src/$(PROJECT_MOD).erl),) +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, []}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]} +]}. +endef +else +define app_file +{application, $(PROJECT), [ + {description, "$(PROJECT_DESCRIPTION)"}, + {vsn, "$(PROJECT_VERSION)"},$(if $(IS_DEP), + {id$(comma)$(space)"$(1)"}$(comma)) + {modules, [$(call comma_list,$(2))]}, + {registered, [$(call comma_list,$(PROJECT)_sup $(PROJECT_REGISTERED))]}, + {applications, [$(call comma_list,kernel stdlib $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS))]}, + {mod, {$(PROJECT_MOD), []}} +]}. +endef +endif + +app-build: ebin/$(PROJECT).app + $(verbose) : + +# Source files. + +ERL_FILES = $(sort $(call core_find,src/,*.erl)) +CORE_FILES = $(sort $(call core_find,src/,*.core)) + +# ASN.1 files. + +ifneq ($(wildcard asn1/),) +ASN1_FILES = $(sort $(call core_find,asn1/,*.asn1)) +ERL_FILES += $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +define compile_asn1 + $(verbose) mkdir -p include/ + $(asn1_verbose) erlc -v -I include/ -o asn1/ +noobj $(1) + $(verbose) mv asn1/*.erl src/ + $(verbose) mv asn1/*.hrl include/ + $(verbose) mv asn1/*.asn1db include/ +endef + +$(PROJECT).d:: $(ASN1_FILES) + $(if $(strip $?),$(call compile_asn1,$?)) +endif + +# SNMP MIB files. + +ifneq ($(wildcard mibs/),) +MIB_FILES = $(sort $(call core_find,mibs/,*.mib)) + +$(PROJECT).d:: $(COMPILE_MIB_FIRST_PATHS) $(MIB_FILES) + $(verbose) mkdir -p include/ priv/mibs/ + $(mib_verbose) erlc -v $(ERLC_MIB_OPTS) -o priv/mibs/ -I priv/mibs/ $? + $(mib_verbose) erlc -o include/ -- $(addprefix priv/mibs/,$(patsubst %.mib,%.bin,$(notdir $?))) +endif + +# Leex and Yecc files. + +XRL_FILES = $(sort $(call core_find,src/,*.xrl)) +XRL_ERL_FILES = $(addprefix src/,$(patsubst %.xrl,%.erl,$(notdir $(XRL_FILES)))) +ERL_FILES += $(XRL_ERL_FILES) + +YRL_FILES = $(sort $(call core_find,src/,*.yrl)) +YRL_ERL_FILES = $(addprefix src/,$(patsubst %.yrl,%.erl,$(notdir $(YRL_FILES)))) +ERL_FILES += $(YRL_ERL_FILES) + +$(PROJECT).d:: $(XRL_FILES) $(YRL_FILES) + $(if $(strip $?),$(xyrl_verbose) erlc -v -o src/ $?) + +# Erlang and Core Erlang files. + +define makedep.erl + E = ets:new(makedep, [bag]), + G = digraph:new([acyclic]), + ErlFiles = lists:usort(string:tokens("$(ERL_FILES)", " ")), + Modules = [{list_to_atom(filename:basename(F, ".erl")), F} || F <- ErlFiles], + Add = fun (Mod, Dep) -> + case lists:keyfind(Dep, 1, Modules) of + false -> ok; + {_, DepFile} -> + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}), + digraph:add_vertex(G, Mod), + digraph:add_vertex(G, Dep), + digraph:add_edge(G, Mod, Dep) + end + end, + AddHd = fun (F, Mod, DepFile) -> + case file:open(DepFile, [read]) of + {error, enoent} -> ok; + {ok, Fd} -> + F(F, Fd, Mod), + {_, ModFile} = lists:keyfind(Mod, 1, Modules), + ets:insert(E, {ModFile, DepFile}) + end + end, + Attr = fun + (F, Mod, behavior, Dep) -> Add(Mod, Dep); + (F, Mod, behaviour, Dep) -> Add(Mod, Dep); + (F, Mod, compile, {parse_transform, Dep}) -> Add(Mod, Dep); + (F, Mod, compile, Opts) when is_list(Opts) -> + case proplists:get_value(parse_transform, Opts) of + undefined -> ok; + Dep -> Add(Mod, Dep) + end; + (F, Mod, include, Hrl) -> + case filelib:is_file("include/" ++ Hrl) of + true -> AddHd(F, Mod, "include/" ++ Hrl); + false -> + case filelib:is_file("src/" ++ Hrl) of + true -> AddHd(F, Mod, "src/" ++ Hrl); + false -> false + end + end; + (F, Mod, include_lib, "$1/include/" ++ Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, include_lib, Hrl) -> AddHd(F, Mod, "include/" ++ Hrl); + (F, Mod, import, {Imp, _}) -> + case filelib:is_file("src/" ++ atom_to_list(Imp) ++ ".erl") of + false -> ok; + true -> Add(Mod, Imp) + end; + (_, _, _, _) -> ok + end, + MakeDepend = fun(F, Fd, Mod) -> + case io:parse_erl_form(Fd, undefined) of + {ok, {attribute, _, Key, Value}, _} -> + Attr(F, Mod, Key, Value), + F(F, Fd, Mod); + {eof, _} -> + file:close(Fd); + _ -> + F(F, Fd, Mod) + end + end, + [begin + Mod = list_to_atom(filename:basename(F, ".erl")), + {ok, Fd} = file:open(F, [read]), + MakeDepend(MakeDepend, Fd, Mod) + end || F <- ErlFiles], + Depend = sofs:to_external(sofs:relation_to_family(sofs:relation(ets:tab2list(E)))), + CompileFirst = [X || X <- lists:reverse(digraph_utils:topsort(G)), [] =/= digraph:in_neighbours(G, X)], + ok = file:write_file("$(1)", [ + [[F, "::", [[" ", D] || D <- Deps], "; @touch \$$@\n"] || {F, Deps} <- Depend], + "\nCOMPILE_FIRST +=", [[" ", atom_to_list(CF)] || CF <- CompileFirst], "\n" + ]), + halt() +endef + +ifeq ($(if $(NO_MAKEDEP),$(wildcard $(PROJECT).d),),) +$(PROJECT).d:: $(ERL_FILES) $(call core_find,include/,*.hrl) $(MAKEFILE_LIST) + $(makedep_verbose) $(call erlang,$(call makedep.erl,$@)) +endif + +ifneq ($(words $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES)),0) +# Rebuild everything when the Makefile changes. +$(ERLANG_MK_TMP)/last-makefile-change: $(MAKEFILE_LIST) + @mkdir -p $(ERLANG_MK_TMP) + @if test -f $@; then \ + touch $(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES); \ + touch -c $(PROJECT).d; \ + fi + @touch $@ + +$(ERL_FILES) $(CORE_FILES) $(ASN1_FILES) $(MIB_FILES) $(XRL_FILES) $(YRL_FILES):: $(ERLANG_MK_TMP)/last-makefile-change +ebin/$(PROJECT).app:: $(ERLANG_MK_TMP)/last-makefile-change +endif + +-include $(PROJECT).d + +ebin/$(PROJECT).app:: ebin/ + +ebin/: + $(verbose) mkdir -p ebin/ + +define compile_erl + $(erlc_verbose) erlc -v $(if $(IS_DEP),$(filter-out -Werror,$(ERLC_OPTS)),$(ERLC_OPTS)) -o ebin/ \ + -pa ebin/ -I include/ $(filter-out $(ERLC_EXCLUDE_PATHS),$(COMPILE_FIRST_PATHS) $(1)) +endef + +ebin/$(PROJECT).app:: $(ERL_FILES) $(CORE_FILES) $(wildcard src/$(PROJECT).app.src) + $(eval FILES_TO_COMPILE := $(filter-out src/$(PROJECT).app.src,$?)) + $(if $(strip $(FILES_TO_COMPILE)),$(call compile_erl,$(FILES_TO_COMPILE))) + $(eval GITDESCRIBE := $(shell git describe --dirty --abbrev=7 --tags --always --first-parent 2>/dev/null || true)) + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename \ + $(filter-out $(ERLC_EXCLUDE_PATHS),$(ERL_FILES) $(CORE_FILES) $(BEAM_FILES))))))) +ifeq ($(wildcard src/$(PROJECT).app.src),) + $(app_verbose) printf "$(subst $(newline),\n,$(subst ",\",$(call app_file,$(GITDESCRIBE),$(MODULES))))" \ + > ebin/$(PROJECT).app +else + $(verbose) if [ -z "$$(grep -e '^[^%]*{\s*modules\s*,' src/$(PROJECT).app.src)" ]; then \ + echo "Empty modules entry not found in $(PROJECT).app.src. Please consult the erlang.mk README for instructions." >&2; \ + exit 1; \ + fi + $(appsrc_verbose) cat src/$(PROJECT).app.src \ + | sed "s/{[[:space:]]*modules[[:space:]]*,[[:space:]]*\[\]}/{modules, \[$(call comma_list,$(MODULES))\]}/" \ + | sed "s/{id,[[:space:]]*\"git\"}/{id, \"$(subst /,\/,$(GITDESCRIBE))\"}/" \ + > ebin/$(PROJECT).app +endif + +clean:: clean-app + +clean-app: + $(gen_verbose) rm -rf $(PROJECT).d ebin/ priv/mibs/ $(XRL_ERL_FILES) $(YRL_ERL_FILES) \ + $(addprefix include/,$(patsubst %.mib,%.hrl,$(notdir $(MIB_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.hrl,$(notdir $(ASN1_FILES)))) \ + $(addprefix include/,$(patsubst %.asn1,%.asn1db,$(notdir $(ASN1_FILES)))) \ + $(addprefix src/,$(patsubst %.asn1,%.erl,$(notdir $(ASN1_FILES)))) + +endif + +# Copyright (c) 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: docs-deps + +# Configuration. + +ALL_DOC_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(DOC_DEPS)) + +# Targets. + +$(foreach dep,$(DOC_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +doc-deps: +else +doc-deps: $(ALL_DOC_DEPS_DIRS) + $(verbose) for dep in $(ALL_DOC_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rel-deps + +# Configuration. + +ALL_REL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(REL_DEPS)) + +# Targets. + +$(foreach dep,$(REL_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +rel-deps: +else +rel-deps: $(ALL_REL_DEPS_DIRS) + $(verbose) for dep in $(ALL_REL_DEPS_DIRS) ; do $(MAKE) -C $$dep; done +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: test-deps test-dir test-build clean-test-dir + +# Configuration. + +TEST_DIR ?= $(CURDIR)/test + +ALL_TEST_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(TEST_DEPS)) + +TEST_ERLC_OPTS ?= +debug_info +warn_export_vars +warn_shadow_vars +warn_obsolete_guard +TEST_ERLC_OPTS += -DTEST=1 + +# Targets. + +$(foreach dep,$(TEST_DEPS),$(eval $(call dep_target,$(dep)))) + +ifneq ($(SKIP_DEPS),) +test-deps: +else +test-deps: $(ALL_TEST_DEPS_DIRS) + $(verbose) for dep in $(ALL_TEST_DEPS_DIRS) ; do $(MAKE) -C $$dep IS_DEP=1; done +endif + +ifneq ($(wildcard $(TEST_DIR)),) +test-dir: + $(gen_verbose) erlc -v $(TEST_ERLC_OPTS) -I include/ -o $(TEST_DIR) \ + $(call core_find,$(TEST_DIR)/,*.erl) -pa ebin/ +endif + +ifeq ($(wildcard src),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps + $(verbose) $(MAKE) --no-print-directory test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +else +ifeq ($(wildcard ebin/test),) +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: clean deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" + $(gen_verbose) touch ebin/test +else +test-build:: ERLC_OPTS=$(TEST_ERLC_OPTS) +test-build:: deps test-deps $(PROJECT).d + $(verbose) $(MAKE) --no-print-directory app-build test-dir ERLC_OPTS="$(TEST_ERLC_OPTS)" +endif + +clean:: clean-test-dir + +clean-test-dir: +ifneq ($(wildcard $(TEST_DIR)/*.beam),) + $(gen_verbose) rm -f $(TEST_DIR)/*.beam +endif +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: rebar.config + +# We strip out -Werror because we don't want to fail due to +# warnings when used as a dependency. + +compat_prepare_erlc_opts = $(shell echo "$1" | sed 's/, */,/g') + +define compat_convert_erlc_opts +$(if $(filter-out -Werror,$1),\ + $(if $(findstring +,$1),\ + $(shell echo $1 | cut -b 2-))) +endef + +define compat_erlc_opts_to_list +[$(call comma_list,$(foreach o,$(call compat_prepare_erlc_opts,$1),$(call compat_convert_erlc_opts,$o)))] +endef + +define compat_rebar_config +{deps, [ +$(call comma_list,$(foreach d,$(DEPS),\ + $(if $(filter hex,$(call dep_fetch,$d)),\ + {$(call dep_name,$d)$(comma)"$(call dep_repo,$d)"},\ + {$(call dep_name,$d)$(comma)".*"$(comma){git,"$(call dep_repo,$d)"$(comma)"$(call dep_commit,$d)"}}))) +]}. +{erl_opts, $(call compat_erlc_opts_to_list,$(ERLC_OPTS))}. +endef + +$(eval _compat_rebar_config = $$(compat_rebar_config)) +$(eval export _compat_rebar_config) + +rebar.config: + $(gen_verbose) echo "$${_compat_rebar_config}" > rebar.config + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: asciidoc asciidoc-guide asciidoc-manual install-asciidoc distclean-asciidoc + +MAN_INSTALL_PATH ?= /usr/local/share/man +MAN_SECTIONS ?= 3 7 + +docs:: asciidoc + +asciidoc: asciidoc-guide asciidoc-manual + +ifeq ($(wildcard doc/src/guide/book.asciidoc),) +asciidoc-guide: +else +asciidoc-guide: distclean-asciidoc doc-deps + a2x -v -f pdf doc/src/guide/book.asciidoc && mv doc/src/guide/book.pdf doc/guide.pdf + a2x -v -f chunked doc/src/guide/book.asciidoc && mv doc/src/guide/book.chunked/ doc/html/ +endif + +ifeq ($(wildcard doc/src/manual/*.asciidoc),) +asciidoc-manual: +else +asciidoc-manual: distclean-asciidoc doc-deps + for f in doc/src/manual/*.asciidoc ; do \ + a2x -v -f manpage $$f ; \ + done + for s in $(MAN_SECTIONS); do \ + mkdir -p doc/man$$s/ ; \ + mv doc/src/manual/*.$$s doc/man$$s/ ; \ + gzip doc/man$$s/*.$$s ; \ + done + +install-docs:: install-asciidoc + +install-asciidoc: asciidoc-manual + for s in $(MAN_SECTIONS); do \ + mkdir -p $(MAN_INSTALL_PATH)/man$$s/ ; \ + install -g `id -u` -o `id -g` -m 0644 doc/man$$s/*.gz $(MAN_INSTALL_PATH)/man$$s/ ; \ + done +endif + +distclean:: distclean-asciidoc + +distclean-asciidoc: + $(gen_verbose) rm -rf doc/html/ doc/guide.pdf doc/man3/ doc/man7/ + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: bootstrap bootstrap-lib bootstrap-rel new list-templates + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Bootstrap targets:" \ + " bootstrap Generate a skeleton of an OTP application" \ + " bootstrap-lib Generate a skeleton of an OTP library" \ + " bootstrap-rel Generate the files needed to build a release" \ + " new-app in=NAME Create a new local OTP application NAME" \ + " new-lib in=NAME Create a new local OTP library NAME" \ + " new t=TPL n=NAME Generate a module NAME based on the template TPL" \ + " new t=T n=N in=APP Generate a module NAME based on the template TPL in APP" \ + " list-templates List available templates" + +# Bootstrap templates. + +define bs_appsrc +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]}, + {mod, {$p_app, []}}, + {env, []} +]}. +endef + +define bs_appsrc_lib +{application, $p, [ + {description, ""}, + {vsn, "0.1.0"}, + {id, "git"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib + ]} +]}. +endef + +# To prevent autocompletion issues with ZSH, we add "include erlang.mk" +# separately during the actual bootstrap. +ifdef SP +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +# Whitespace to be used when creating files from templates. +SP = $(SP) + +endef +else +define bs_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +endef +endif + +define bs_apps_Makefile +PROJECT = $p +PROJECT_DESCRIPTION = New project +PROJECT_VERSION = 0.0.1 + +include $(call core_relpath,$(dir $(ERLANG_MK_FILENAME)),$(APPS_DIR)/app)/erlang.mk +endef + +define bs_app +-module($p_app). +-behaviour(application). + +-export([start/2]). +-export([stop/1]). + +start(_Type, _Args) -> + $p_sup:start_link(). + +stop(_State) -> + ok. +endef + +define bs_relx_config +{release, {$p_release, "1"}, [$p]}. +{extended_start_script, true}. +{sys_config, "rel/sys.config"}. +{vm_args, "rel/vm.args"}. +endef + +define bs_sys_config +[ +]. +endef + +define bs_vm_args +-name $p@127.0.0.1 +-setcookie $p +-heart +endef + +# Normal templates. + +define tpl_supervisor +-module($(n)). +-behaviour(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + Procs = [], + {ok, {{one_for_one, 1, 5}, Procs}}. +endef + +define tpl_gen_server +-module($(n)). +-behaviour(gen_server). + +%% API. +-export([start_link/0]). + +%% gen_server. +-export([init/1]). +-export([handle_call/3]). +-export([handle_cast/2]). +-export([handle_info/2]). +-export([terminate/2]). +-export([code_change/3]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_server:start_link(?MODULE, [], []). + +%% gen_server. + +init([]) -> + {ok, #state{}}. + +handle_call(_Request, _From, State) -> + {reply, ignored, State}. + +handle_cast(_Msg, State) -> + {noreply, State}. + +handle_info(_Info, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. +endef + +define tpl_module +-module($(n)). +-export([]). +endef + +define tpl_cowboy_http +-module($(n)). +-behaviour(cowboy_http_handler). + +-export([init/3]). +-export([handle/2]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {ok, Req, #state{}}. + +handle(Req, State=#state{}) -> + {ok, Req2} = cowboy_req:reply(200, Req), + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_gen_fsm +-module($(n)). +-behaviour(gen_fsm). + +%% API. +-export([start_link/0]). + +%% gen_fsm. +-export([init/1]). +-export([state_name/2]). +-export([handle_event/3]). +-export([state_name/3]). +-export([handle_sync_event/4]). +-export([handle_info/3]). +-export([terminate/3]). +-export([code_change/4]). + +-record(state, { +}). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> + gen_fsm:start_link(?MODULE, [], []). + +%% gen_fsm. + +init([]) -> + {ok, state_name, #state{}}. + +state_name(_Event, StateData) -> + {next_state, state_name, StateData}. + +handle_event(_Event, StateName, StateData) -> + {next_state, StateName, StateData}. + +state_name(_Event, _From, StateData) -> + {reply, ignored, state_name, StateData}. + +handle_sync_event(_Event, _From, StateName, StateData) -> + {reply, ignored, StateName, StateData}. + +handle_info(_Info, StateName, StateData) -> + {next_state, StateName, StateData}. + +terminate(_Reason, _StateName, _StateData) -> + ok. + +code_change(_OldVsn, StateName, StateData, _Extra) -> + {ok, StateName, StateData}. +endef + +define tpl_cowboy_loop +-module($(n)). +-behaviour(cowboy_loop_handler). + +-export([init/3]). +-export([info/3]). +-export([terminate/3]). + +-record(state, { +}). + +init(_, Req, _Opts) -> + {loop, Req, #state{}, 5000, hibernate}. + +info(_Info, Req, State) -> + {loop, Req, State, hibernate}. + +terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_cowboy_rest +-module($(n)). + +-export([init/3]). +-export([content_types_provided/2]). +-export([get_html/2]). + +init(_, _Req, _Opts) -> + {upgrade, protocol, cowboy_rest}. + +content_types_provided(Req, State) -> + {[{{<<"text">>, <<"html">>, '*'}, get_html}], Req, State}. + +get_html(Req, State) -> + {<<"This is REST!">>, Req, State}. +endef + +define tpl_cowboy_ws +-module($(n)). +-behaviour(cowboy_websocket_handler). + +-export([init/3]). +-export([websocket_init/3]). +-export([websocket_handle/3]). +-export([websocket_info/3]). +-export([websocket_terminate/3]). + +-record(state, { +}). + +init(_, _, _) -> + {upgrade, protocol, cowboy_websocket}. + +websocket_init(_, Req, _Opts) -> + Req2 = cowboy_req:compact(Req), + {ok, Req2, #state{}}. + +websocket_handle({text, Data}, Req, State) -> + {reply, {text, Data}, Req, State}; +websocket_handle({binary, Data}, Req, State) -> + {reply, {binary, Data}, Req, State}; +websocket_handle(_Frame, Req, State) -> + {ok, Req, State}. + +websocket_info(_Info, Req, State) -> + {ok, Req, State}. + +websocket_terminate(_Reason, _Req, _State) -> + ok. +endef + +define tpl_ranch_protocol +-module($(n)). +-behaviour(ranch_protocol). + +-export([start_link/4]). +-export([init/4]). + +-type opts() :: []. +-export_type([opts/0]). + +-record(state, { + socket :: inet:socket(), + transport :: module() +}). + +start_link(Ref, Socket, Transport, Opts) -> + Pid = spawn_link(?MODULE, init, [Ref, Socket, Transport, Opts]), + {ok, Pid}. + +-spec init(ranch:ref(), inet:socket(), module(), opts()) -> ok. +init(Ref, Socket, Transport, _Opts) -> + ok = ranch:accept_ack(Ref), + loop(#state{socket=Socket, transport=Transport}). + +loop(State) -> + loop(State). +endef + +# Plugin-specific targets. + +define render_template + $(verbose) printf -- '$(subst $(newline),\n,$(subst %,%%,$(subst ','\'',$(subst $(tab),$(WS),$(call $(1))))))\n' > $(2) +endef + +ifndef WS +ifdef SP +WS = $(subst a,,a $(wordlist 1,$(SP),a a a a a a a a a a a a a a a a a a a a)) +else +WS = $(tab) +endif +endif + +bootstrap: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(eval n := $(PROJECT)_sup) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc,src/$(PROJECT).app.src) +endif + $(call render_template,bs_app,src/$(PROJECT)_app.erl) + $(call render_template,tpl_supervisor,src/$(PROJECT)_sup.erl) + +bootstrap-lib: +ifneq ($(wildcard src/),) + $(error Error: src/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_Makefile,Makefile) + $(verbose) echo "include erlang.mk" >> Makefile + $(verbose) mkdir src/ +ifdef LEGACY + $(call render_template,bs_appsrc_lib,src/$(PROJECT).app.src) +endif + +bootstrap-rel: +ifneq ($(wildcard relx.config),) + $(error Error: relx.config already exists) +endif +ifneq ($(wildcard rel/),) + $(error Error: rel/ directory already exists) +endif + $(eval p := $(PROJECT)) + $(call render_template,bs_relx_config,relx.config) + $(verbose) mkdir rel/ + $(call render_template,bs_sys_config,rel/sys.config) + $(call render_template,bs_vm_args,rel/vm.args) + +new-app: +ifndef in + $(error Usage: $(MAKE) new-app in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(eval n := $(in)_sup) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc,$(APPS_DIR)/$p/src/$p.app.src) +endif + $(call render_template,bs_app,$(APPS_DIR)/$p/src/$p_app.erl) + $(call render_template,tpl_supervisor,$(APPS_DIR)/$p/src/$p_sup.erl) + +new-lib: +ifndef in + $(error Usage: $(MAKE) new-lib in=APP) +endif +ifneq ($(wildcard $(APPS_DIR)/$in),) + $(error Error: Application $in already exists) +endif + $(eval p := $(in)) + $(verbose) mkdir -p $(APPS_DIR)/$p/src/ + $(call render_template,bs_apps_Makefile,$(APPS_DIR)/$p/Makefile) +ifdef LEGACY + $(call render_template,bs_appsrc_lib,$(APPS_DIR)/$p/src/$p.app.src) +endif + +new: +ifeq ($(wildcard src/)$(in),) + $(error Error: src/ directory does not exist) +endif +ifndef t + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifndef tpl_$(t) + $(error Unknown template) +endif +ifndef n + $(error Usage: $(MAKE) new t=TEMPLATE n=NAME [in=APP]) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new t=$t n=$n in= +else + $(call render_template,tpl_$(t),src/$(n).erl) +endif + +list-templates: + $(verbose) echo Available templates: $(sort $(patsubst tpl_%,%,$(filter tpl_%,$(.VARIABLES)))) + +# Copyright (c) 2014-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: clean-c_src distclean-c_src-env + +# Configuration. + +C_SRC_DIR ?= $(CURDIR)/c_src +C_SRC_ENV ?= $(C_SRC_DIR)/env.mk +C_SRC_OUTPUT ?= $(CURDIR)/priv/$(PROJECT) +C_SRC_TYPE ?= shared + +# System type and C compiler/flags. + +ifeq ($(PLATFORM),msys2) + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= .exe + C_SRC_OUTPUT_SHARED_EXTENSION ?= .dll +else + C_SRC_OUTPUT_EXECUTABLE_EXTENSION ?= + C_SRC_OUTPUT_SHARED_EXTENSION ?= .so +endif + +ifeq ($(C_SRC_TYPE),shared) + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_SHARED_EXTENSION) +else + C_SRC_OUTPUT_FILE = $(C_SRC_OUTPUT)$(C_SRC_OUTPUT_EXECUTABLE_EXTENSION) +endif + +ifeq ($(PLATFORM),msys2) +# We hardcode the compiler used on MSYS2. The default CC=cc does +# not produce working code. The "gcc" MSYS2 package also doesn't. + CC = /mingw64/bin/gcc + export CC + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),darwin) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall + LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress +else ifeq ($(PLATFORM),freebsd) + CC ?= cc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +else ifeq ($(PLATFORM),linux) + CC ?= gcc + CFLAGS ?= -O3 -std=c99 -finline-functions -Wall -Wmissing-prototypes + CXXFLAGS ?= -O3 -finline-functions -Wall +endif + +ifneq ($(PLATFORM),msys2) + CFLAGS += -fPIC + CXXFLAGS += -fPIC +endif + +CFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" +CXXFLAGS += -I"$(ERTS_INCLUDE_DIR)" -I"$(ERL_INTERFACE_INCLUDE_DIR)" + +LDLIBS += -L"$(ERL_INTERFACE_LIB_DIR)" -lerl_interface -lei + +# Verbosity. + +c_verbose_0 = @echo " C " $(?F); +c_verbose = $(c_verbose_$(V)) + +cpp_verbose_0 = @echo " CPP " $(?F); +cpp_verbose = $(cpp_verbose_$(V)) + +link_verbose_0 = @echo " LD " $(@F); +link_verbose = $(link_verbose_$(V)) + +# Targets. + +ifeq ($(wildcard $(C_SRC_DIR)),) +else ifneq ($(wildcard $(C_SRC_DIR)/Makefile),) +app:: app-c_src + +test-build:: app-c_src + +app-c_src: + $(MAKE) -C $(C_SRC_DIR) + +clean:: + $(MAKE) -C $(C_SRC_DIR) clean + +else + +ifeq ($(SOURCES),) +SOURCES := $(sort $(foreach pat,*.c *.C *.cc *.cpp,$(call core_find,$(C_SRC_DIR)/,$(pat)))) +endif +OBJECTS = $(addsuffix .o, $(basename $(SOURCES))) + +COMPILE_C = $(c_verbose) $(CC) $(CFLAGS) $(CPPFLAGS) -c +COMPILE_CPP = $(cpp_verbose) $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c + +app:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +test-build:: $(C_SRC_ENV) $(C_SRC_OUTPUT_FILE) + +$(C_SRC_OUTPUT_FILE): $(OBJECTS) + $(verbose) mkdir -p priv/ + $(link_verbose) $(CC) $(OBJECTS) \ + $(LDFLAGS) $(if $(filter $(C_SRC_TYPE),shared),-shared) $(LDLIBS) \ + -o $(C_SRC_OUTPUT_FILE) + +%.o: %.c + $(COMPILE_C) $(OUTPUT_OPTION) $< + +%.o: %.cc + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.C + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +%.o: %.cpp + $(COMPILE_CPP) $(OUTPUT_OPTION) $< + +clean:: clean-c_src + +clean-c_src: + $(gen_verbose) rm -f $(C_SRC_OUTPUT_FILE) $(OBJECTS) + +endif + +ifneq ($(wildcard $(C_SRC_DIR)),) +$(C_SRC_ENV): + $(verbose) $(ERL) -eval "file:write_file(\"$(call core_native_path,$(C_SRC_ENV))\", \ + io_lib:format( \ + \"ERTS_INCLUDE_DIR ?= ~s/erts-~s/include/~n\" \ + \"ERL_INTERFACE_INCLUDE_DIR ?= ~s~n\" \ + \"ERL_INTERFACE_LIB_DIR ?= ~s~n\", \ + [code:root_dir(), erlang:system_info(version), \ + code:lib_dir(erl_interface, include), \ + code:lib_dir(erl_interface, lib)])), \ + halt()." + +distclean:: distclean-c_src-env + +distclean-c_src-env: + $(gen_verbose) rm -f $(C_SRC_ENV) + +-include $(C_SRC_ENV) +endif + +# Templates. + +define bs_c_nif +#include "erl_nif.h" + +static int loads = 0; + +static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ + /* Initialize private data. */ + *priv_data = NULL; + + loads++; + + return 0; +} + +static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info) +{ + /* Convert the private data to the new version. */ + *priv_data = *old_priv_data; + + loads++; + + return 0; +} + +static void unload(ErlNifEnv* env, void* priv_data) +{ + if (loads == 1) { + /* Destroy the private data. */ + } + + loads--; +} + +static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + if (enif_is_atom(env, argv[0])) { + return enif_make_tuple2(env, + enif_make_atom(env, "hello"), + argv[0]); + } + + return enif_make_tuple2(env, + enif_make_atom(env, "error"), + enif_make_atom(env, "badarg")); +} + +static ErlNifFunc nif_funcs[] = { + {"hello", 1, hello} +}; + +ERL_NIF_INIT($n, nif_funcs, load, NULL, upgrade, unload) +endef + +define bs_erl_nif +-module($n). + +-export([hello/1]). + +-on_load(on_load/0). +on_load() -> + PrivDir = case code:priv_dir(?MODULE) of + {error, _} -> + AppPath = filename:dirname(filename:dirname(code:which(?MODULE))), + filename:join(AppPath, "priv"); + Path -> + Path + end, + erlang:load_nif(filename:join(PrivDir, atom_to_list(?MODULE)), 0). + +hello(_) -> + erlang:nif_error({not_loaded, ?MODULE}). +endef + +new-nif: +ifneq ($(wildcard $(C_SRC_DIR)/$n.c),) + $(error Error: $(C_SRC_DIR)/$n.c already exists) +endif +ifneq ($(wildcard src/$n.erl),) + $(error Error: src/$n.erl already exists) +endif +ifdef in + $(verbose) $(MAKE) -C $(APPS_DIR)/$(in)/ new-nif n=$n in= +else + $(verbose) mkdir -p $(C_SRC_DIR) src/ + $(call render_template,bs_c_nif,$(C_SRC_DIR)/$n.c) + $(call render_template,bs_erl_nif,src/$n.erl) +endif + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ci ci-setup distclean-kerl + +KERL ?= $(CURDIR)/kerl +export KERL + +KERL_URL ?= https://raw.githubusercontent.com/yrashk/kerl/master/kerl + +OTP_GIT ?= https://github.com/erlang/otp + +CI_INSTALL_DIR ?= $(HOME)/erlang +CI_OTP ?= + +ifeq ($(strip $(CI_OTP)),) +ci:: +else +ci:: $(addprefix ci-,$(CI_OTP)) + +ci-prepare: $(addprefix $(CI_INSTALL_DIR)/,$(CI_OTP)) + +ci-setup:: + +ci_verbose_0 = @echo " CI " $(1); +ci_verbose = $(ci_verbose_$(V)) + +define ci_target +ci-$(1): $(CI_INSTALL_DIR)/$(1) + $(ci_verbose) \ + PATH="$(CI_INSTALL_DIR)/$(1)/bin:$(PATH)" \ + CI_OTP_RELEASE="$(1)" \ + CT_OPTS="-label $(1)" \ + $(MAKE) clean ci-setup tests +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_target,$(otp)))) + +define ci_otp_target +ifeq ($(wildcard $(CI_INSTALL_DIR)/$(1)),) +$(CI_INSTALL_DIR)/$(1): $(KERL) + $(KERL) build git $(OTP_GIT) $(1) $(1) + $(KERL) install $(1) $(CI_INSTALL_DIR)/$(1) +endif +endef + +$(foreach otp,$(CI_OTP),$(eval $(call ci_otp_target,$(otp)))) + +$(KERL): + $(gen_verbose) $(call core_http_get,$(KERL),$(KERL_URL)) + $(verbose) chmod +x $(KERL) + +help:: + $(verbose) printf "%s\n" "" \ + "Continuous Integration targets:" \ + " ci Run '$(MAKE) tests' on all configured Erlang versions." \ + "" \ + "The CI_OTP variable must be defined with the Erlang versions" \ + "that must be tested. For example: CI_OTP = OTP-17.3.4 OTP-17.5.3" + +distclean:: distclean-kerl + +distclean-kerl: + $(gen_verbose) rm -rf $(KERL) +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: ct apps-ct distclean-ct + +# Configuration. + +CT_OPTS ?= +ifneq ($(wildcard $(TEST_DIR)),) + CT_SUITES ?= $(sort $(subst _SUITE.erl,,$(notdir $(call core_find,$(TEST_DIR)/,*_SUITE.erl)))) +else + CT_SUITES ?= +endif + +# Core targets. + +tests:: ct + +distclean:: distclean-ct + +help:: + $(verbose) printf "%s\n" "" \ + "Common_test targets:" \ + " ct Run all the common_test suites for this project" \ + "" \ + "All your common_test suites have their associated targets." \ + "A suite named http_SUITE can be ran using the ct-http target." + +# Plugin-specific targets. + +CT_RUN = ct_run \ + -no_auto_compile \ + -noinput \ + -pa $(CURDIR)/ebin $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(TEST_DIR) \ + -dir $(TEST_DIR) \ + -logdir $(CURDIR)/logs + +ifeq ($(CT_SUITES),) +ct: $(if $(IS_APP),,apps-ct) +else +ct: test-build $(if $(IS_APP),,apps-ct) + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(CT_SUITES)) $(CT_OPTS) +endif + +ifneq ($(ALL_APPS_DIRS),) +define ct_app_target +apps-ct-$1: + $(MAKE) -C $1 ct IS_APP=1 +endef + +$(foreach app,$(ALL_APPS_DIRS),$(eval $(call ct_app_target,$(app)))) + +apps-ct: test-build $(addprefix apps-ct-,$(ALL_APPS_DIRS)) +endif + +ifndef t +CT_EXTRA = +else +ifeq (,$(findstring :,$t)) +CT_EXTRA = -group $t +else +t_words = $(subst :, ,$t) +CT_EXTRA = -group $(firstword $(t_words)) -case $(lastword $(t_words)) +endif +endif + +define ct_suite_target +ct-$(1): test-build + $(verbose) mkdir -p $(CURDIR)/logs/ + $(gen_verbose) $(CT_RUN) -sname ct_$(PROJECT) -suite $(addsuffix _SUITE,$(1)) $(CT_EXTRA) $(CT_OPTS) +endef + +$(foreach test,$(CT_SUITES),$(eval $(call ct_suite_target,$(test)))) + +distclean-ct: + $(gen_verbose) rm -rf $(CURDIR)/logs/ + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: plt distclean-plt dialyze + +# Configuration. + +DIALYZER_PLT ?= $(CURDIR)/.$(PROJECT).plt +export DIALYZER_PLT + +PLT_APPS ?= +DIALYZER_DIRS ?= --src -r $(wildcard src) $(ALL_APPS_DIRS) +DIALYZER_OPTS ?= -Werror_handling -Wrace_conditions -Wunmatched_returns # -Wunderspecs + +# Core targets. + +check:: dialyze + +distclean:: distclean-plt + +help:: + $(verbose) printf "%s\n" "" \ + "Dialyzer targets:" \ + " plt Build a PLT file for this project" \ + " dialyze Analyze the project using Dialyzer" + +# Plugin-specific targets. + +define filter_opts.erl + Opts = init:get_plain_arguments(), + {Filtered, _} = lists:foldl(fun + (O, {Os, true}) -> {[O|Os], false}; + (O = "-D", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$D, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-I", {Os, _}) -> {[O|Os], true}; + (O = [\\$$-, \\$$I, _ | _], {Os, _}) -> {[O|Os], false}; + (O = "-pa", {Os, _}) -> {[O|Os], true}; + (_, Acc) -> Acc + end, {[], false}, Opts), + io:format("~s~n", [string:join(lists:reverse(Filtered), " ")]), + halt(). +endef + +$(DIALYZER_PLT): deps app + $(verbose) dialyzer --build_plt --apps erts kernel stdlib $(PLT_APPS) $(OTP_DEPS) $(LOCAL_DEPS) $(DEPS) + +plt: $(DIALYZER_PLT) + +distclean-plt: + $(gen_verbose) rm -f $(DIALYZER_PLT) + +ifneq ($(wildcard $(DIALYZER_PLT)),) +dialyze: +else +dialyze: $(DIALYZER_PLT) +endif + $(verbose) dialyzer --no_native `$(ERL) -eval "$(subst $(newline),,$(subst ",\",$(call filter_opts.erl)))" -extra $(ERLC_OPTS)` $(DIALYZER_DIRS) $(DIALYZER_OPTS) + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-edoc edoc + +# Configuration. + +EDOC_OPTS ?= + +# Core targets. + +ifneq ($(wildcard doc/overview.edoc),) +docs:: edoc +endif + +distclean:: distclean-edoc + +# Plugin-specific targets. + +edoc: distclean-edoc doc-deps + $(gen_verbose) $(ERL) -eval 'edoc:application($(PROJECT), ".", [$(EDOC_OPTS)]), halt().' + +distclean-edoc: + $(gen_verbose) rm -f doc/*.css doc/*.html doc/*.png doc/edoc-info + +# Copyright (c) 2014 Dave Cottlehuber +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: distclean-escript escript + +# Configuration. + +ESCRIPT_NAME ?= $(PROJECT) +ESCRIPT_FILE ?= $(ESCRIPT_NAME) + +ESCRIPT_COMMENT ?= This is an -*- erlang -*- file + +ESCRIPT_BEAMS ?= "ebin/*", "deps/*/ebin/*" +ESCRIPT_SYS_CONFIG ?= "rel/sys.config" +ESCRIPT_EMU_ARGS ?= -pa . \ + -sasl errlog_type error \ + -escript main $(ESCRIPT_NAME) +ESCRIPT_SHEBANG ?= /usr/bin/env escript +ESCRIPT_STATIC ?= "deps/*/priv/**", "priv/**" + +# Core targets. + +distclean:: distclean-escript + +help:: + $(verbose) printf "%s\n" "" \ + "Escript targets:" \ + " escript Build an executable escript archive" \ + +# Plugin-specific targets. + +# Based on https://github.com/synrc/mad/blob/master/src/mad_bundle.erl +# Copyright (c) 2013 Maxim Sokhatsky, Synrc Research Center +# Modified MIT License, https://github.com/synrc/mad/blob/master/LICENSE : +# Software may only be used for the great good and the true happiness of all +# sentient beings. + +define ESCRIPT_RAW +'Read = fun(F) -> {ok, B} = file:read_file(filename:absname(F)), B end,'\ +'Files = fun(L) -> A = lists:concat([filelib:wildcard(X)||X<- L ]),'\ +' [F || F <- A, not filelib:is_dir(F) ] end,'\ +'Squash = fun(L) -> [{filename:basename(F), Read(F) } || F <- L ] end,'\ +'Zip = fun(A, L) -> {ok,{_,Z}} = zip:create(A, L, [{compress,all},memory]), Z end,'\ +'Ez = fun(Escript) ->'\ +' Static = Files([$(ESCRIPT_STATIC)]),'\ +' Beams = Squash(Files([$(ESCRIPT_BEAMS), $(ESCRIPT_SYS_CONFIG)])),'\ +' Archive = Beams ++ [{ "static.gz", Zip("static.gz", Static)}],'\ +' escript:create(Escript, [ $(ESCRIPT_OPTIONS)'\ +' {archive, Archive, [memory]},'\ +' {shebang, "$(ESCRIPT_SHEBANG)"},'\ +' {comment, "$(ESCRIPT_COMMENT)"},'\ +' {emu_args, " $(ESCRIPT_EMU_ARGS)"}'\ +' ]),'\ +' file:change_mode(Escript, 8#755)'\ +'end,'\ +'Ez("$(ESCRIPT_FILE)"),'\ +'halt().' +endef + +ESCRIPT_COMMAND = $(subst ' ',,$(ESCRIPT_RAW)) + +escript:: distclean-escript deps app + $(gen_verbose) $(ERL) -eval $(ESCRIPT_COMMAND) + +distclean-escript: + $(gen_verbose) rm -f $(ESCRIPT_NAME) + +# Copyright (c) 2014, Enrique Fernandez +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: eunit apps-eunit + +# Configuration + +EUNIT_OPTS ?= +EUNIT_ERL_OPTS ?= + +# Core targets. + +tests:: eunit + +help:: + $(verbose) printf "%s\n" "" \ + "EUnit targets:" \ + " eunit Run all the EUnit tests for this project" + +# Plugin-specific targets. + +define eunit.erl + case "$(COVER)" of + "" -> ok; + _ -> + case cover:compile_beam_directory("ebin") of + {error, _} -> halt(1); + _ -> ok + end + end, + case eunit:test($1, [$(EUNIT_OPTS)]) of + ok -> ok; + error -> halt(2) + end, + case "$(COVER)" of + "" -> ok; + _ -> + cover:export("eunit.coverdata") + end, + halt() +endef + +EUNIT_ERL_OPTS += -pa $(TEST_DIR) $(DEPS_DIR)/*/ebin $(APPS_DIR)/*/ebin $(CURDIR)/ebin + +ifdef t +ifeq (,$(findstring :,$(t))) +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,['$(t)']),$(EUNIT_ERL_OPTS)) +else +eunit: test-build + $(gen_verbose) $(call erlang,$(call eunit.erl,fun $(t)/0),$(EUNIT_ERL_OPTS)) +endif +else +EUNIT_EBIN_MODS = $(notdir $(basename $(ERL_FILES) $(BEAM_FILES))) +EUNIT_TEST_MODS = $(notdir $(basename $(call core_find,$(TEST_DIR)/,*.erl))) + +EUNIT_MODS = $(foreach mod,$(EUNIT_EBIN_MODS) $(filter-out \ + $(patsubst %,%_tests,$(EUNIT_EBIN_MODS)),$(EUNIT_TEST_MODS)),'$(mod)') + +eunit: test-build $(if $(IS_APP),,apps-eunit) + $(gen_verbose) $(call erlang,$(call eunit.erl,[$(call comma_list,$(EUNIT_MODS))]),$(EUNIT_ERL_OPTS)) + +ifneq ($(ALL_APPS_DIRS),) +apps-eunit: + $(verbose) for app in $(ALL_APPS_DIRS); do $(MAKE) -C $$app eunit IS_APP=1; done +endif +endif + +# Copyright (c) 2013-2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: relx-rel distclean-relx-rel distclean-relx run + +# Configuration. + +RELX ?= $(CURDIR)/relx +RELX_CONFIG ?= $(CURDIR)/relx.config + +RELX_URL ?= https://github.com/erlware/relx/releases/download/v3.19.0/relx +RELX_OPTS ?= +RELX_OUTPUT_DIR ?= _rel + +ifeq ($(firstword $(RELX_OPTS)),-o) + RELX_OUTPUT_DIR = $(word 2,$(RELX_OPTS)) +else + RELX_OPTS += -o $(RELX_OUTPUT_DIR) +endif + +# Core targets. + +ifeq ($(IS_DEP),) +ifneq ($(wildcard $(RELX_CONFIG)),) +rel:: relx-rel +endif +endif + +distclean:: distclean-relx-rel distclean-relx + +# Plugin-specific targets. + +$(RELX): + $(gen_verbose) $(call core_http_get,$(RELX),$(RELX_URL)) + $(verbose) chmod +x $(RELX) + +relx-rel: $(RELX) rel-deps app + $(verbose) $(RELX) -c $(RELX_CONFIG) $(RELX_OPTS) + +distclean-relx-rel: + $(gen_verbose) rm -rf $(RELX_OUTPUT_DIR) + +distclean-relx: + $(gen_verbose) rm -rf $(RELX) + +# Run target. + +ifeq ($(wildcard $(RELX_CONFIG)),) +run: +else + +define get_relx_release.erl + {ok, Config} = file:consult("$(RELX_CONFIG)"), + {release, {Name, _}, _} = lists:keyfind(release, 1, Config), + io:format("~s", [Name]), + halt(0). +endef + +RELX_RELEASE = `$(call erlang,$(get_relx_release.erl))` + +run: all + $(verbose) $(RELX_OUTPUT_DIR)/$(RELX_RELEASE)/bin/$(RELX_RELEASE) console + +help:: + $(verbose) printf "%s\n" "" \ + "Relx targets:" \ + " run Compile the project, build the release and run it" + +endif + +# Copyright (c) 2014, M Robert Martin +# Copyright (c) 2015, Loïc Hoguin +# This file is contributed to erlang.mk and subject to the terms of the ISC License. + +.PHONY: shell + +# Configuration. + +SHELL_ERL ?= erl +SHELL_PATHS ?= $(CURDIR)/ebin $(APPS_DIR)/*/ebin $(DEPS_DIR)/*/ebin +SHELL_OPTS ?= + +ALL_SHELL_DEPS_DIRS = $(addprefix $(DEPS_DIR)/,$(SHELL_DEPS)) + +# Core targets + +help:: + $(verbose) printf "%s\n" "" \ + "Shell targets:" \ + " shell Run an erlang shell with SHELL_OPTS or reasonable default" + +# Plugin-specific targets. + +$(foreach dep,$(SHELL_DEPS),$(eval $(call dep_target,$(dep)))) + +build-shell-deps: $(ALL_SHELL_DEPS_DIRS) + $(verbose) for dep in $(ALL_SHELL_DEPS_DIRS) ; do $(MAKE) -C $$dep ; done + +shell: build-shell-deps + $(gen_verbose) $(SHELL_ERL) -pa $(SHELL_PATHS) $(SHELL_OPTS) + +# Copyright (c) 2015, Loïc Hoguin +# This file is part of erlang.mk and subject to the terms of the ISC License. + +ifeq ($(filter triq,$(DEPS) $(TEST_DEPS)),triq) +.PHONY: triq + +# Targets. + +tests:: triq + +define triq_check.erl + code:add_pathsa(["$(CURDIR)/ebin", "$(DEPS_DIR)/*/ebin"]), + try + case $(1) of + all -> [true] =:= lists:usort([triq:check(M) || M <- [$(call comma_list,$(3))]]); + module -> triq:check($(2)); + function -> triq:check($(2)) + end + of + true -> halt(0); + _ -> halt(1) + catch error:undef -> + io:format("Undefined property or module~n"), + halt(0) + end. +endef + +ifdef t +ifeq (,$(findstring :,$(t))) +triq: test-build + $(verbose) $(call erlang,$(call triq_check.erl,module,$(t))) +else +triq: test-build + $(verbose) echo Testing $(t)/0 + $(verbose) $(call erlang,$(call triq_check.erl,function,$(t)())) +endif +else +triq: test-build + $(eval MODULES := $(patsubst %,'%',$(sort $(notdir $(basename $(wildcard ebin/*.beam)))))) + $(gen_verbose) $(call erlang,$(call triq_check.erl,all,undefined,$(MODULES))) +endif +endif + +# Copyright (c) 2015, Erlang Solutions Ltd. +# This file is part of erlang.mk and subject to the terms of the ISC License. + +.PHONY: xref distclean-xref + +# Configuration. + +ifeq ($(XREF_CONFIG),) + XREFR_ARGS := +else + XREFR_ARGS := -c $(XREF_CONFIG) +endif + +XREFR ?= $(CURDIR)/xrefr +export XREFR + +XREFR_URL ?= https://github.com/inaka/xref_runner/releases/download/0.2.2/xrefr + +# Core targets. + +help:: + $(verbose) printf "%s\n" "" \ + "Xref targets:" \ + " xref Run Xrefr using $XREF_CONFIG as config file if defined" + +distclean:: distclean-xref + +# Plugin-specific targets. + +$(XREFR): + $(gen_verbose) $(call core_http_get,$(XREFR),$(XREFR_URL)) + $(verbose) chmod +x $(XREFR) + +xref: deps app $(XREFR) + $(gen_verbose) $(XREFR) $(XREFR_ARGS) + +distclean-xref: + $(gen_verbose) rm -rf $(XREFR) + +# Copyright 2015, Viktor Söderqvist +# This file is part of erlang.mk and subject to the terms of the ISC License. + +COVER_REPORT_DIR = cover + +# Hook in coverage to ct + +ifdef COVER +ifdef CT_RUN +# All modules in 'ebin' +COVER_MODS = $(notdir $(basename $(call core_ls,ebin/*.beam))) + +test-build:: $(TEST_DIR)/ct.cover.spec + +$(TEST_DIR)/ct.cover.spec: + $(verbose) echo Cover mods: $(COVER_MODS) + $(gen_verbose) printf "%s\n" \ + '{incl_mods,[$(subst $(space),$(comma),$(COVER_MODS))]}.' \ + '{export,"$(CURDIR)/ct.coverdata"}.' > $@ + +CT_RUN += -cover $(TEST_DIR)/ct.cover.spec +endif +endif + +# Core targets + +ifdef COVER +ifneq ($(COVER_REPORT_DIR),) +tests:: + $(verbose) $(MAKE) --no-print-directory cover-report +endif +endif + +clean:: coverdata-clean + +ifneq ($(COVER_REPORT_DIR),) +distclean:: cover-report-clean +endif + +help:: + $(verbose) printf "%s\n" "" \ + "Cover targets:" \ + " cover-report Generate a HTML coverage report from previously collected" \ + " cover data." \ + " all.coverdata Merge {eunit,ct}.coverdata into one coverdata file." \ + "" \ + "If COVER=1 is set, coverage data is generated by the targets eunit and ct. The" \ + "target tests additionally generates a HTML coverage report from the combined" \ + "coverdata files from each of these testing tools. HTML reports can be disabled" \ + "by setting COVER_REPORT_DIR to empty." + +# Plugin specific targets + +COVERDATA = $(filter-out all.coverdata,$(wildcard *.coverdata)) + +.PHONY: coverdata-clean +coverdata-clean: + $(gen_verbose) rm -f *.coverdata ct.cover.spec + +# Merge all coverdata files into one. +all.coverdata: $(COVERDATA) + $(gen_verbose) $(ERL) -eval ' \ + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) \ + cover:export("$@"), halt(0).' + +# These are only defined if COVER_REPORT_DIR is non-empty. Set COVER_REPORT_DIR to +# empty if you want the coverdata files but not the HTML report. +ifneq ($(COVER_REPORT_DIR),) + +.PHONY: cover-report-clean cover-report + +cover-report-clean: + $(gen_verbose) rm -rf $(COVER_REPORT_DIR) + +ifeq ($(COVERDATA),) +cover-report: +else + +# Modules which include eunit.hrl always contain one line without coverage +# because eunit defines test/0 which is never called. We compensate for this. +EUNIT_HRL_MODS = $(subst $(space),$(comma),$(shell \ + grep -e '^\s*-include.*include/eunit\.hrl"' src/*.erl \ + | sed "s/^src\/\(.*\)\.erl:.*/'\1'/" | uniq)) + +define cover_report.erl + $(foreach f,$(COVERDATA),cover:import("$(f)") == ok orelse halt(1),) + Ms = cover:imported_modules(), + [cover:analyse_to_file(M, "$(COVER_REPORT_DIR)/" ++ atom_to_list(M) + ++ ".COVER.html", [html]) || M <- Ms], + Report = [begin {ok, R} = cover:analyse(M, module), R end || M <- Ms], + EunitHrlMods = [$(EUNIT_HRL_MODS)], + Report1 = [{M, {Y, case lists:member(M, EunitHrlMods) of + true -> N - 1; false -> N end}} || {M, {Y, N}} <- Report], + TotalY = lists:sum([Y || {_, {Y, _}} <- Report1]), + TotalN = lists:sum([N || {_, {_, N}} <- Report1]), + Perc = fun(Y, N) -> case Y + N of 0 -> 100; S -> round(100 * Y / S) end end, + TotalPerc = Perc(TotalY, TotalN), + {ok, F} = file:open("$(COVER_REPORT_DIR)/index.html", [write]), + io:format(F, "~n" + "~n" + "Coverage report~n" + "~n", []), + io:format(F, "

Coverage

~n

Total: ~p%

~n", [TotalPerc]), + io:format(F, "~n", []), + [io:format(F, "" + "~n", + [M, M, Perc(Y, N)]) || {M, {Y, N}} <- Report1], + How = "$(subst $(space),$(comma)$(space),$(basename $(COVERDATA)))", + Date = "$(shell date -u "+%Y-%m-%dT%H:%M:%SZ")", + io:format(F, "
ModuleCoverage
~p~p%
~n" + "

Generated using ~s and erlang.mk on ~s.

~n" + "", [How, Date]), + halt(). +endef + +cover-report: + $(gen_verbose) mkdir -p $(COVER_REPORT_DIR) + $(gen_verbose) $(call erlang,$(cover_report.erl)) + +endif +endif # ifneq ($(COVER_REPORT_DIR),) + +# Copyright (c) 2013-2015, Loïc Hoguin +# Copyright (c) 2015-2016, Jean-Sébastien Pédron +# This file is part of erlang.mk and subject to the terms of the ISC License. + +# Fetch dependencies recursively (without building them). + +.PHONY: fetch-deps fetch-doc-deps fetch-rel-deps fetch-test-deps \ + fetch-shell-deps + +.PHONY: $(ERLANG_MK_RECURSIVE_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ + $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +fetch-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +fetch-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +fetch-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +fetch-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +fetch-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +ifneq ($(SKIP_DEPS),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): + $(verbose) :> $@ +else +# By default, we fetch "normal" dependencies. They are also included no +# matter the type of requested dependencies. +# +# $(ALL_DEPS_DIRS) includes $(BUILD_DEPS). + +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_DOC_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_REL_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_TEST_DEPS_DIRS) +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): $(ALL_DEPS_DIRS) $(ALL_SHELL_DEPS_DIRS) + +# Allow to use fetch-deps and $(DEP_TYPES) to fetch multiple types of +# dependencies with a single target. +ifneq ($(filter doc,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_DOC_DEPS_DIRS) +endif +ifneq ($(filter rel,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_REL_DEPS_DIRS) +endif +ifneq ($(filter test,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_TEST_DEPS_DIRS) +endif +ifneq ($(filter shell,$(DEP_TYPES)),) +$(ERLANG_MK_RECURSIVE_DEPS_LIST): $(ALL_SHELL_DEPS_DIRS) +endif + +ERLANG_MK_RECURSIVE_TMP_LIST := $(abspath $(ERLANG_MK_TMP)/recursive-tmp-deps.log) + +$(ERLANG_MK_RECURSIVE_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) \ +$(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST): +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) mkdir -p $(ERLANG_MK_TMP) + $(verbose) rm -f $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +ifndef IS_APP + $(verbose) for dep in $(ALL_APPS_DIRS) ; do \ + $(MAKE) -C $$dep $@ \ + IS_APP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + done +endif + $(verbose) for dep in $^ ; do \ + if ! grep -qs ^$$dep$$ $(ERLANG_MK_RECURSIVE_TMP_LIST); then \ + echo $$dep >> $(ERLANG_MK_RECURSIVE_TMP_LIST); \ + if grep -qs -E "^[[:blank:]]*include[[:blank:]]+(erlang\.mk|.*/erlang\.mk)$$" \ + $$dep/GNUmakefile $$dep/makefile $$dep/Makefile; then \ + $(MAKE) -C $$dep fetch-deps \ + IS_DEP=1 \ + ERLANG_MK_RECURSIVE_TMP_LIST=$(ERLANG_MK_RECURSIVE_TMP_LIST) \ + || exit $$?; \ + fi \ + fi \ + done +ifeq ($(IS_APP)$(IS_DEP),) + $(verbose) sort < $(ERLANG_MK_RECURSIVE_TMP_LIST) | uniq > $@ + $(verbose) rm $(ERLANG_MK_RECURSIVE_TMP_LIST) +endif +endif # ifneq ($(SKIP_DEPS),) + +# List dependencies recursively. + +.PHONY: list-deps list-doc-deps list-rel-deps list-test-deps \ + list-shell-deps + +list-deps: $(ERLANG_MK_RECURSIVE_DEPS_LIST) +list-doc-deps: $(ERLANG_MK_RECURSIVE_DOC_DEPS_LIST) +list-rel-deps: $(ERLANG_MK_RECURSIVE_REL_DEPS_LIST) +list-test-deps: $(ERLANG_MK_RECURSIVE_TEST_DEPS_LIST) +list-shell-deps: $(ERLANG_MK_RECURSIVE_SHELL_DEPS_LIST) + +list-deps list-doc-deps list-rel-deps list-test-deps list-shell-deps: + $(verbose) cat $^ diff --git a/deps/rabbitmq_web_dispatch/rabbitmq-components.mk b/deps/rabbitmq_web_dispatch/rabbitmq-components.mk new file mode 100644 index 0000000..05986d8 --- /dev/null +++ b/deps/rabbitmq_web_dispatch/rabbitmq-components.mk @@ -0,0 +1,284 @@ +ifeq ($(.DEFAULT_GOAL),) +# Define default goal to `all` because this file defines some targets +# before the inclusion of erlang.mk leading to the wrong target becoming +# the default. +.DEFAULT_GOAL = all +endif + +# -------------------------------------------------------------------- +# RabbitMQ components. +# -------------------------------------------------------------------- + +# For RabbitMQ repositories, we want to checkout branches which match +# the parent project. For instance, if the parent project is on a +# release tag, dependencies must be on the same release tag. If the +# parent project is on a topic branch, dependencies must be on the same +# topic branch or fallback to `stable` or `master` whichever was the +# base of the topic branch. + +dep_amqp_client = git_rmq rabbitmq-erlang-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit = git_rmq rabbitmq-server $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbit_common = git_rmq rabbitmq-common $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_amqp1_0 = git_rmq rabbitmq-amqp1.0 $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_amqp = git_rmq rabbitmq-auth-backend-amqp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_http = git_rmq rabbitmq-auth-backend-http $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_backend_ldap = git_rmq rabbitmq-auth-backend-ldap $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_auth_mechanism_ssl = git_rmq rabbitmq-auth-mechanism-ssl $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_boot_steps_visualiser = git_rmq rabbitmq-boot-steps-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_clusterer = git_rmq rabbitmq-clusterer $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_codegen = git_rmq rabbitmq-codegen $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_consistent_hash_exchange = git_rmq rabbitmq-consistent-hash-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_ct_helpers = git_rmq rabbitmq-ct-helpers $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_delayed_message_exchange = git_rmq rabbitmq-delayed-message-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_dotnet_client = git_rmq rabbitmq-dotnet-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_event_exchange = git_rmq rabbitmq-event-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation = git_rmq rabbitmq-federation $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_federation_management = git_rmq rabbitmq-federation-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_java_client = git_rmq rabbitmq-java-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_client = git_rmq rabbitmq-jms-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_jms_topic_exchange = git_rmq rabbitmq-jms-topic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_lvc = git_rmq rabbitmq-lvc-plugin $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management = git_rmq rabbitmq-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_agent = git_rmq rabbitmq-management-agent $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_exchange = git_rmq rabbitmq-management-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_themes = git_rmq rabbitmq-management-themes $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_management_visualiser = git_rmq rabbitmq-management-visualiser $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_message_timestamp = git_rmq rabbitmq-message-timestamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_metronome = git_rmq rabbitmq-metronome $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_mqtt = git_rmq rabbitmq-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_objc_client = git_rmq rabbitmq-objc-client $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_recent_history_exchange = git_rmq rabbitmq-recent-history-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_routing_node_stamp = git_rmq rabbitmq-routing-node-stamp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_rtopic_exchange = git_rmq rabbitmq-rtopic-exchange $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_server_release = git_rmq rabbitmq-server-release $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_sharding = git_rmq rabbitmq-sharding $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel = git_rmq rabbitmq-shovel $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_shovel_management = git_rmq rabbitmq-shovel-management $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_stomp = git_rmq rabbitmq-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_toke = git_rmq rabbitmq-toke $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_top = git_rmq rabbitmq-top $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_tracing = git_rmq rabbitmq-tracing $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_trust_store = git_rmq rabbitmq-trust-store $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_test = git_rmq rabbitmq-test $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_dispatch = git_rmq rabbitmq-web-dispatch $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp = git_rmq rabbitmq-web-stomp $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_stomp_examples = git_rmq rabbitmq-web-stomp-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt = git_rmq rabbitmq-web-mqtt $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_web_mqtt_examples = git_rmq rabbitmq-web-mqtt-examples $(current_rmq_ref) $(base_rmq_ref) master +dep_rabbitmq_website = git_rmq rabbitmq-website $(current_rmq_ref) $(base_rmq_ref) live master +dep_sockjs = git_rmq sockjs-erlang $(current_rmq_ref) $(base_rmq_ref) master +dep_toke = git_rmq toke $(current_rmq_ref) $(base_rmq_ref) master + +dep_rabbitmq_public_umbrella = git_rmq rabbitmq-public-umbrella $(current_rmq_ref) $(base_rmq_ref) master + +# FIXME: As of 2015-11-20, we depend on Ranch 1.2.1, but erlang.mk +# defaults to Ranch 1.1.0. All projects depending indirectly on Ranch +# needs to add "ranch" as a BUILD_DEPS. The list of projects needing +# this workaround are: +# o rabbitmq-web-stomp +dep_ranch = git https://github.com/ninenines/ranch 1.2.1 + +RABBITMQ_COMPONENTS = amqp_client \ + rabbit \ + rabbit_common \ + rabbitmq_amqp1_0 \ + rabbitmq_auth_backend_amqp \ + rabbitmq_auth_backend_http \ + rabbitmq_auth_backend_ldap \ + rabbitmq_auth_mechanism_ssl \ + rabbitmq_boot_steps_visualiser \ + rabbitmq_clusterer \ + rabbitmq_codegen \ + rabbitmq_consistent_hash_exchange \ + rabbitmq_ct_helpers \ + rabbitmq_delayed_message_exchange \ + rabbitmq_dotnet_client \ + rabbitmq_event_exchange \ + rabbitmq_federation \ + rabbitmq_federation_management \ + rabbitmq_java_client \ + rabbitmq_jms_client \ + rabbitmq_jms_topic_exchange \ + rabbitmq_lvc \ + rabbitmq_management \ + rabbitmq_management_agent \ + rabbitmq_management_exchange \ + rabbitmq_management_themes \ + rabbitmq_management_visualiser \ + rabbitmq_message_timestamp \ + rabbitmq_metronome \ + rabbitmq_mqtt \ + rabbitmq_objc_client \ + rabbitmq_recent_history_exchange \ + rabbitmq_routing_node_stamp \ + rabbitmq_rtopic_exchange \ + rabbitmq_server_release \ + rabbitmq_sharding \ + rabbitmq_shovel \ + rabbitmq_shovel_management \ + rabbitmq_stomp \ + rabbitmq_toke \ + rabbitmq_top \ + rabbitmq_tracing \ + rabbitmq_trust_store \ + rabbitmq_web_dispatch \ + rabbitmq_web_mqtt \ + rabbitmq_web_mqtt_examples \ + rabbitmq_web_stomp \ + rabbitmq_web_stomp_examples \ + rabbitmq_website + +# Several components have a custom erlang.mk/build.config, mainly +# to disable eunit. Therefore, we can't use the top-level project's +# erlang.mk copy. +NO_AUTOPATCH += $(RABBITMQ_COMPONENTS) + +ifeq ($(origin current_rmq_ref),undefined) +ifneq ($(wildcard .git),) +current_rmq_ref := $(shell (\ + ref=$$(git branch --list | awk '/^\* \(.*detached / {ref=$$0; sub(/.*detached [^ ]+ /, "", ref); sub(/\)$$/, "", ref); print ref; exit;} /^\* / {ref=$$0; sub(/^\* /, "", ref); print ref; exit}');\ + if test "$$(git rev-parse --short HEAD)" != "$$ref"; then echo "$$ref"; fi)) +else +current_rmq_ref := master +endif +endif +export current_rmq_ref + +ifeq ($(origin base_rmq_ref),undefined) +ifneq ($(wildcard .git),) +base_rmq_ref := $(shell \ + (git rev-parse --verify -q stable >/dev/null && \ + git merge-base --is-ancestor $$(git merge-base master HEAD) stable && \ + echo stable) || \ + echo master) +else +base_rmq_ref := master +endif +endif +export base_rmq_ref + +# Repository URL selection. +# +# First, we infer other components' location from the current project +# repository URL, if it's a Git repository: +# - We take the "origin" remote URL as the base +# - The current project name and repository name is replaced by the +# target's properties: +# eg. rabbitmq-common is replaced by rabbitmq-codegen +# eg. rabbit_common is replaced by rabbitmq_codegen +# +# If cloning from this computed location fails, we fallback to RabbitMQ +# upstream which is GitHub. + +# Maccro to transform eg. "rabbit_common" to "rabbitmq-common". +rmq_cmp_repo_name = $(word 2,$(dep_$(1))) + +# Upstream URL for the current project. +RABBITMQ_COMPONENT_REPO_NAME := $(call rmq_cmp_repo_name,$(PROJECT)) +RABBITMQ_UPSTREAM_FETCH_URL ?= https://github.com/rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git +RABBITMQ_UPSTREAM_PUSH_URL ?= git@github.com:rabbitmq/$(RABBITMQ_COMPONENT_REPO_NAME).git + +# Current URL for the current project. If this is not a Git clone, +# default to the upstream Git repository. +ifneq ($(wildcard .git),) +git_origin_fetch_url := $(shell git config remote.origin.url) +git_origin_push_url := $(shell git config remote.origin.pushurl || git config remote.origin.url) +RABBITMQ_CURRENT_FETCH_URL ?= $(git_origin_fetch_url) +RABBITMQ_CURRENT_PUSH_URL ?= $(git_origin_push_url) +else +RABBITMQ_CURRENT_FETCH_URL ?= $(RABBITMQ_UPSTREAM_FETCH_URL) +RABBITMQ_CURRENT_PUSH_URL ?= $(RABBITMQ_UPSTREAM_PUSH_URL) +endif + +# Macro to replace the following pattern: +# 1. /foo.git -> /bar.git +# 2. /foo -> /bar +# 3. /foo/ -> /bar/ +subst_repo_name = $(patsubst %/$(1)/%,%/$(2)/%,$(patsubst %/$(1),%/$(2),$(patsubst %/$(1).git,%/$(2).git,$(3)))) + +# Macro to replace both the project's name (eg. "rabbit_common") and +# repository name (eg. "rabbitmq-common") by the target's equivalent. +# +# This macro is kept on one line because we don't want whitespaces in +# the returned value, as it's used in $(dep_fetch_git_rmq) in a shell +# single-quoted string. +dep_rmq_repo = $(if $(dep_$(2)),$(call subst_repo_name,$(PROJECT),$(2),$(call subst_repo_name,$(RABBITMQ_COMPONENT_REPO_NAME),$(call rmq_cmp_repo_name,$(2)),$(1))),$(pkg_$(1)_repo)) + +dep_rmq_commits = $(if $(dep_$(1)), \ + $(wordlist 3,$(words $(dep_$(1))),$(dep_$(1))), \ + $(pkg_$(1)_commit)) + +define dep_fetch_git_rmq + fetch_url1='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_FETCH_URL),$(1))'; \ + fetch_url2='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_FETCH_URL),$(1))'; \ + if test "$$$$fetch_url1" != '$(RABBITMQ_CURRENT_FETCH_URL)' && \ + git clone -q -n -- "$$$$fetch_url1" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url1"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_CURRENT_PUSH_URL),$(1))'; \ + elif git clone -q -n -- "$$$$fetch_url2" $(DEPS_DIR)/$(call dep_name,$(1)); then \ + fetch_url="$$$$fetch_url2"; \ + push_url='$(call dep_rmq_repo,$(RABBITMQ_UPSTREAM_PUSH_URL),$(1))'; \ + fi; \ + cd $(DEPS_DIR)/$(call dep_name,$(1)) && ( \ + $(foreach ref,$(call dep_rmq_commits,$(1)), \ + git checkout -q $(ref) >/dev/null 2>&1 || \ + ) \ + (echo "error: no valid pathspec among: $(call dep_rmq_commits,$(1))" \ + 1>&2 && false) ) && \ + (test "$$$$fetch_url" = "$$$$push_url" || \ + git remote set-url --push origin "$$$$push_url") +endef + +# -------------------------------------------------------------------- +# Component distribution. +# -------------------------------------------------------------------- + +list-dist-deps:: + @: + +prepare-dist:: + @: + +# -------------------------------------------------------------------- +# rabbitmq-components.mk checks. +# -------------------------------------------------------------------- + +# If this project is under the Umbrella project, we override $(DEPS_DIR) +# to point to the Umbrella's one. We also disable `make distclean` so +# $(DEPS_DIR) is not accidentally removed. + +ifneq ($(wildcard ../../UMBRELLA.md),) +UNDER_UMBRELLA = 1 +else ifneq ($(wildcard UMBRELLA.md),) +UNDER_UMBRELLA = 1 +endif + +ifeq ($(UNDER_UMBRELLA),1) +ifneq ($(PROJECT),rabbitmq_public_umbrella) +DEPS_DIR ?= $(abspath ..) +endif + +ifneq ($(filter distclean distclean-deps,$(MAKECMDGOALS)),) +SKIP_DEPS = 1 +endif +endif + +UPSTREAM_RMQ_COMPONENTS_MK = $(DEPS_DIR)/rabbit_common/mk/rabbitmq-components.mk + +check-rabbitmq-components.mk: + $(verbose) cmp -s rabbitmq-components.mk \ + $(UPSTREAM_RMQ_COMPONENTS_MK) || \ + (echo "error: rabbitmq-components.mk must be updated!" 1>&2; \ + false) + +ifeq ($(PROJECT),rabbit_common) +rabbitmq-components-mk: + @: +else +rabbitmq-components-mk: + $(gen_verbose) cp -a $(UPSTREAM_RMQ_COMPONENTS_MK) . +ifeq ($(DO_COMMIT),yes) + $(verbose) git diff --quiet rabbitmq-components.mk \ + || git commit -m 'Update rabbitmq-components.mk' rabbitmq-components.mk +endif +endif diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl similarity index 60% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl rename to deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl index 6fd7539..5a7481d 100644 --- a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl +++ b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_web_dispatch). @@ -50,16 +50,27 @@ register_static_context(Name, Listener, Prefix, Module, FSPath, LinkText) -> register_port_redirect(Name, Listener, Prefix, RedirectPort) -> register_context_handler( Name, Listener, Prefix, - cowboy_router:compile([{'_', [{'_', rabbit_cowboy_redirect, RedirectPort}]}]), + fun (Req) -> + Host = case Req:get_header_value("host") of + undefined -> {ok, {IP, _Port}} = rabbit_net:sockname( + Req:get(socket)), + rabbit_misc:ntoa(IP); + Header -> hd(string:tokens(Header, ":")) + end, + URL = rabbit_misc:format( + "~s://~s:~B~s", + [Req:get(scheme), Host, RedirectPort, Req:get(raw_path)]), + Req:respond({301, [{"Location", URL}], ""}) + end, rabbit_misc:format("Redirect to port ~B", [RedirectPort])). context_selector("") -> fun(_Req) -> true end; context_selector(Prefix) -> - Prefix1 = list_to_binary("/" ++ Prefix), + Prefix1 = "/" ++ Prefix, fun(Req) -> - {Path, _} = cowboy_req:path(Req), - (Path == Prefix1) orelse (binary:match(Path, << Prefix1/binary, $/ >>) =/= nomatch) + Path = Req:get(raw_path), + (Path == Prefix1) orelse (string:str(Path, Prefix1 ++ "/") == 1) end. %% Produces a handler for use with register_handler that serves up @@ -70,10 +81,32 @@ static_context_handler(Prefix, Module, FSPath) -> {file, Here} = code:is_loaded(Module), ModuleRoot = filename:dirname(filename:dirname(Here)), LocalPath = filename:join(ModuleRoot, FSPath), - cowboy_router:compile([{'_', [ - {"/" ++ Prefix, cowboy_static, {file, LocalPath ++ "/index.html"}}, - {"/" ++ Prefix ++ "/[...]", cowboy_static, {dir, LocalPath}} - ]}]). + static_context_handler(Prefix, LocalPath). + +%% Produces a handler for use with register_handler that serves up +%% static content from a specified directory. +static_context_handler("", LocalPath) -> + fun(Req) -> + "/" ++ Path = Req:get(path), + serve_file(Req, Path, LocalPath) + end; +static_context_handler(Prefix, LocalPath) -> + fun(Req) -> + "/" ++ Path = Req:get(path), + case string:substr(Path, length(Prefix) + 1) of + "" -> Req:respond({301, [{"Location", "/" ++ Prefix ++ "/"}], ""}); + "/" ++ P -> serve_file(Req, P, LocalPath) + end + end. + +serve_file(Req, Path, LocalPath) -> + case Req:get(method) of + Method when Method =:= 'GET'; Method =:= 'HEAD' -> + Req:serve_file(Path, LocalPath); + _ -> + Req:respond({405, [{"Allow", "GET, HEAD"}], + "Only GET or HEAD supported for static content"}) + end. %% The opposite of all those register_* functions. unregister_context(Name) -> diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl similarity index 93% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl rename to deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl index 8241711..9dd2117 100644 --- a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl +++ b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_app.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_web_dispatch_app). diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl similarity index 76% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl rename to deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl index d24be10..ff651ee 100644 --- a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl +++ b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_registry.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_web_dispatch_registry). @@ -22,9 +22,6 @@ -export([add/5, remove/1, set_fallback/2, lookup/2, list_all/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([list/1]). - --import(rabbit_misc, [pget/2]). -define(ETS, rabbitmq_web_dispatch). @@ -41,8 +38,6 @@ add(Name, Listener, Selector, Handler, Link) -> remove(Name) -> gen_server:call(?MODULE, {remove, Name}, infinity). -%% @todo This needs to be dispatch instead of a fun too. -%% But I'm not sure what code is using this. set_fallback(Listener, FallbackHandler) -> gen_server:call(?MODULE, {set_fallback, Listener, FallbackHandler}, infinity). @@ -51,9 +46,9 @@ lookup(Listener, Req) -> case lookup_dispatch(Listener) of {ok, {Selectors, Fallback}} -> case catch match_request(Selectors, Req) of - {'EXIT', Reason} -> {error, {lookup_failure, Reason}}; - not_found -> {ok, Fallback}; - Dispatch -> {ok, Dispatch} + {'EXIT', Reason} -> {lookup_failure, Reason}; + no_handler -> {handler, Fallback}; + Handler -> {handler, Handler} end; Err -> Err @@ -76,7 +71,6 @@ handle_call({add, Name, Listener, Selector, Handler, Link = {_, Desc}}, _From, new -> set_dispatch( Listener, [], listing_fallback_handler(Listener)), - listener_started(Listener), true; existing -> true; ignore -> false @@ -103,8 +97,7 @@ handle_call({remove, Name}, _From, Selectors1 = lists:keydelete(Name, 1, Selectors), set_dispatch(Listener, Selectors1, Fallback), case Selectors1 of - [] -> rabbit_web_dispatch_sup:stop_listener(Listener), - listener_stopped(Listener); + [] -> rabbit_web_dispatch_sup:stop_listener(Listener); _ -> ok end, {reply, ok, undefined}; @@ -123,44 +116,26 @@ handle_call(Req, _From, State) -> {stop, unknown_request, State}. handle_cast(_, State) -> - {noreply, State}. + {noreply, State}. handle_info(_, State) -> - {noreply, State}. + {noreply, State}. terminate(_, _) -> true = ets:delete(?ETS), ok. code_change(_, State, _) -> - {ok, State}. + {ok, State}. %%--------------------------------------------------------------------------- %% Internal Methods -listener_started(Listener) -> - [rabbit_networking:tcp_listener_started(Protocol, Listener, IPAddress, Port) - || {Protocol, IPAddress, Port} <- listener_info(Listener)], - ok. - -listener_stopped(Listener) -> - [rabbit_networking:tcp_listener_stopped(Protocol, Listener, IPAddress, Port) - || {Protocol, IPAddress, Port} <- listener_info(Listener)], - ok. - -listener_info(Listener) -> - Protocol = case pget(ssl, Listener) of - true -> https; - _ -> http - end, - Port = pget(port, Listener), - [{Protocol, IPAddress, Port} - || {IPAddress, _Port, _Family} - <- rabbit_networking:tcp_listener_addresses(Port)]. +port(Listener) -> proplists:get_value(port, Listener). lookup_dispatch(Lsnr) -> - case ets:lookup(?ETS, pget(port, Lsnr)) of + case ets:lookup(?ETS, port(Lsnr)) of [{_, Lsnr, S, F}] -> {ok, {S, F}}; [{_, Lsnr2, S, _F}] -> {error, {different, first_desc(S), Lsnr2}}; [] -> {error, {no_record_for_listener, Lsnr}} @@ -169,13 +144,13 @@ lookup_dispatch(Lsnr) -> first_desc([{_N, _S, _H, {_, Desc}} | _]) -> Desc. set_dispatch(Listener, Selectors, Fallback) -> - ets:insert(?ETS, {pget(port, Listener), Listener, Selectors, Fallback}). + ets:insert(?ETS, {port(Listener), Listener, Selectors, Fallback}). match_request([], _) -> - not_found; -match_request([{_Name, Selector, Dispatch, _Link}|Rest], Req) -> + no_handler; +match_request([{_Name, Selector, Handler, _Link}|Rest], Req) -> case Selector(Req) of - true -> Dispatch; + true -> Handler; false -> match_request(Rest, Req) end. @@ -200,6 +175,25 @@ list(Listener) -> %%--------------------------------------------------------------------------- listing_fallback_handler(Listener) -> - cowboy_router:compile([{'_', [ - {"/", rabbit_web_dispatch_listing_handler, Listener} - ]}]). + fun(Req) -> + HTMLPrefix = + "" + "RabbitMQ Web Server" + "

RabbitMQ Web Server

Contexts available:

    ", + HTMLSuffix = "
", + {ReqPath, _, _} = mochiweb_util:urlsplit_path(Req:get(raw_path)), + List = + case list(Listener) of + [] -> + "
  • No contexts installed
  • "; + Contexts -> + [handler_listing(Path, ReqPath, Desc) + || {Path, Desc} <- Contexts] + end, + Req:respond({200, [], HTMLPrefix ++ List ++ HTMLSuffix}) + end. + +handler_listing(Path, ReqPath, Desc) -> + io_lib:format( + "
  • ~s
  • ", + [rabbit_web_dispatch_util:relativise(ReqPath, "/" ++ Path), Desc]). diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl similarity index 59% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl rename to deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl index e89825d..22a293f 100644 --- a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl +++ b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_sup.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_web_dispatch_sup). @@ -36,14 +36,9 @@ ensure_listener(Listener) -> undefined -> {error, {no_port_given, Listener}}; _ -> - {Transport, TransportOpts, ProtoOpts} = preprocess_config(Listener), - Child = ranch:child_spec(name(Listener), 100, - Transport, TransportOpts, - cowboy_protocol, [ - {env, [{rabbit_listener, Listener}]}, - {middlewares, [rabbit_cowboy_middleware, cowboy_router, cowboy_handler]}, - {onresponse, fun rabbit_cowboy_middleware:onresponse/4} - | ProtoOpts]), + Child = {{rabbit_web_dispatch_web, name(Listener)}, + {mochiweb_http, start, [mochi_options(Listener)]}, + transient, 5000, worker, dynamic}, case supervisor:start_child(?SUP, Child) of {ok, _} -> new; {error, {already_started, _}} -> existing; @@ -53,8 +48,8 @@ ensure_listener(Listener) -> stop_listener(Listener) -> Name = name(Listener), - ok = supervisor:terminate_child(?SUP, {ranch_listener_sup, Name}), - ok = supervisor:delete_child(?SUP, {ranch_listener_sup, Name}). + ok = supervisor:terminate_child(?SUP, {rabbit_web_dispatch_web, Name}), + ok = supervisor:delete_child(?SUP, {rabbit_web_dispatch_web, Name}). %% @spec init([[instance()]]) -> SupervisorTree %% @doc supervisor callback. @@ -62,28 +57,43 @@ init([]) -> Registry = {rabbit_web_dispatch_registry, {rabbit_web_dispatch_registry, start_link, []}, transient, 5000, worker, dynamic}, - Log = {rabbit_mgmt_access_logger, {gen_event, start_link, - [{local, webmachine_log_event}]}, - permanent, 5000, worker, [dynamic]}, - {ok, {{one_for_one, 10, 10}, [Registry, Log]}}. + {ok, {{one_for_one, 10, 10}, [Registry]}}. %% ---------------------------------------------------------------------- +mochi_options(Listener) -> + [{name, name(Listener)}, + {loop, loopfun(Listener)} | + ssl_config(proplists:delete( + name, proplists:delete(ignore_in_use, Listener)))]. + +loopfun(Listener) -> + fun (Req) -> + case rabbit_web_dispatch_registry:lookup(Listener, Req) of + no_handler -> + Req:not_found(); + {error, Reason} -> + Req:respond({500, [], "Registry Error: " ++ Reason}); + {handler, Handler} -> + Handler(Req) + end + end. + name(Listener) -> Port = proplists:get_value(port, Listener), list_to_atom(atom_to_list(?MODULE) ++ "_" ++ integer_to_list(Port)). -preprocess_config(Options) -> +ssl_config(Options) -> case proplists:get_value(ssl, Options) of - true -> _ = rabbit_networking:ensure_ssl(), + true -> rabbit_networking:ensure_ssl(), case rabbit_networking:poodle_check('HTTP') of ok -> case proplists:get_value(ssl_opts, Options) of undefined -> auto_ssl(Options); _ -> fix_ssl(Options) end; - danger -> {ranch_tcp, transport_config(Options), protocol_config(Options)} + danger -> proplists:delete(ssl, Options) end; - _ -> {ranch_tcp, transport_config(Options), protocol_config(Options)} + _ -> Options end. auto_ssl(Options) -> @@ -95,32 +105,8 @@ auto_ssl(Options) -> fix_ssl(Options) -> SSLOpts = proplists:get_value(ssl_opts, Options), - {ranch_ssl, - transport_config(Options ++ rabbit_networking:fix_ssl_options(SSLOpts)), - protocol_config(Options)}. - -transport_config(Options0) -> - Options = proplists:delete(ssl, - proplists:delete(ssl_opts, - proplists:delete(cowboy_opts, - Options0))), - case proplists:get_value(ip, Options) of - undefined -> - Options; - IP when is_tuple(IP) -> - Options; - IP when is_list(IP) -> - {ok, ParsedIP} = inet_parse:address(IP), - [{ip, ParsedIP}|proplists:delete(ip, Options)] - end. - -protocol_config(Options) -> - ProtoOpts = proplists:get_value(cowboy_opts, Options, []), - %% Compress responses by default. - case lists:keyfind(compress, 1, ProtoOpts) of - false -> [{compress, true}|ProtoOpts]; - _ -> ProtoOpts - end. + rabbit_misc:pset(ssl_opts, + rabbit_networking:fix_ssl_options(SSLOpts), Options). check_error(Listener, Error) -> Ignore = proplists:get_value(ignore_in_use, Listener, false), diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl similarity index 96% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl rename to deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl index 5bff1a4..f8c116f 100644 --- a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl +++ b/deps/rabbitmq_web_dispatch/src/rabbit_web_dispatch_util.erl @@ -11,7 +11,7 @@ %% The Original Code is RabbitMQ. %% %% The Initial Developer of the Original Code is GoPivotal, Inc. -%% Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. %% -module(rabbit_web_dispatch_util). @@ -19,7 +19,6 @@ -export([parse_auth_header/1]). -export([relativise/2, unrelativise/2]). -%% @todo remove parse_auth_header(Header) -> case Header of "Basic " ++ Base64 -> diff --git a/deps/rabbitmq_web_dispatch/src/rabbit_webmachine.erl b/deps/rabbitmq_web_dispatch/src/rabbit_webmachine.erl new file mode 100644 index 0000000..a199a31 --- /dev/null +++ b/deps/rabbitmq_web_dispatch/src/rabbit_webmachine.erl @@ -0,0 +1,68 @@ +%% This file contains an adapted version of webmachine_mochiweb:loop/1 +%% from webmachine (revision 0c4b60ac68b4). + +%% All modifications are (C) 2011-2013 GoPivotal, Inc. + +-module(rabbit_webmachine). + +%% An alternative to webmachine_mochiweb, which places the dispatch +%% table (among other things) into the application env, and thereby +%% makes it impossible to run more than one instance of +%% webmachine. Since rabbit_web_dispatch is all about multi-tenanting +%% webapps, clearly this won't do for us. + +%% Instead of using webmachine_mochiweb:start/1 or +%% webmachine_mochiweb:loop/1, construct a loop procedure using +%% makeloop/1 and supply it as the argument to +%% rabbit_web_dispatch:register_context_handler or to mochiweb_http:start. + +%% We hardwire the "error handler" and use a "logging module" if +%% supplied. + +-export([makeloop/1, setup/0]). + +setup() -> + application:set_env( + webmachine, error_handler, rabbit_webmachine_error_handler). + +makeloop(Dispatch) -> + fun (MochiReq) -> + Req = webmachine:new_request(mochiweb, MochiReq), + {Path, _} = Req:path(), + {ReqData, _} = Req:get_reqdata(), + %% webmachine_mochiweb:loop/1 uses dispatch/4 here; + %% however, we don't need to dispatch by the host name. + case webmachine_dispatcher:dispatch(Path, Dispatch, ReqData) of + {no_dispatch_match, _Host, _PathElements} -> + {ErrorBody, ReqState1} = + rabbit_webmachine_error_handler:render_error( + 404, Req, {none, none, []}), + Req1 = {webmachine_request, ReqState1}, + {ok, ReqState2} = Req1:append_to_response_body(ErrorBody), + Req2 = {webmachine_request, ReqState2}, + {ok, ReqState3} = Req2:send_response(404), + maybe_log_access(ReqState3); + {Mod, ModOpts, HostTokens, Port, PathTokens, Bindings, + AppRoot, StringPath} -> + BootstrapResource = webmachine_resource:new(x,x,x,x), + {ok, Resource} = BootstrapResource:wrap(Mod, ModOpts), + {ok, RS1} = Req:load_dispatch_data(Bindings, HostTokens, Port, + PathTokens, + AppRoot, StringPath), + XReq1 = {webmachine_request, RS1}, + {ok, RS2} = XReq1:set_metadata('resource_module', Mod), + try + webmachine_decision_core:handle_request(Resource, RS2) + catch + error:_ -> + FailReq = {webmachine_request, RS2}, + {ok, RS3} = FailReq:send_response(500), + maybe_log_access(RS3) + end + end + end. + +maybe_log_access(ReqState) -> + Req = {webmachine_request, ReqState}, + {LogData, _ReqState1} = Req:log_data(), + webmachine_log:log_access(LogData). diff --git a/deps/rabbitmq_web_dispatch/src/rabbit_webmachine_error_handler.erl b/deps/rabbitmq_web_dispatch/src/rabbit_webmachine_error_handler.erl new file mode 100644 index 0000000..3d11529 --- /dev/null +++ b/deps/rabbitmq_web_dispatch/src/rabbit_webmachine_error_handler.erl @@ -0,0 +1,63 @@ +%% The contents of this file are subject to the Mozilla Public License +%% Version 1.1 (the "License"); you may not use this file except in +%% compliance with the License. You may obtain a copy of the License +%% at http://www.mozilla.org/MPL/ +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and +%% limitations under the License. +%% +%% The Original Code is RabbitMQ. +%% +%% The Initial Developer of the Original Code is GoPivotal, Inc. +%% Copyright (c) 2007-2016 Pivotal Software, Inc. All rights reserved. +%% + +%% We need to ensure all responses are application/json; anything +%% coming back as text/html could constitute an XSS vector. Also I'm +%% sure it's easier on our clients if they can always expect JSON +%% responses. +%% +%% Based on webmachine_error_handler, but I'm not sure enough remains +%% to be copyrightable. + +-module(rabbit_webmachine_error_handler). + +-export([render_error/3]). + +render_error(Code, Req, Reason) -> + case Req:has_response_body() of + {true, _} -> + maybe_log(Req, Reason), + {Body, ReqState0} = Req:response_body(), + {ok, ReqState} = + webmachine_request:remove_response_header("Content-Encoding", + ReqState0), + {Body, ReqState}; + {false, _} -> render_error_body(Code, Req:trim_state(), Reason) + end. + +render_error_body(404, Req, _) -> error_body(404, Req, "Not Found"); +render_error_body(Code, Req, Reason) -> error_body(Code, Req, Reason). + +error_body(Code, Req, Reason) -> + {ok, _ReqState0} = Req:add_response_header("Content-Type","application/json"), + {ok, ReqState} = Req:remove_response_header("Content-Encoding"), + case Code of + 500 -> maybe_log(Req, Reason); + _ -> ok + end, + Json = {struct, + [{error, list_to_binary(httpd_util:reason_phrase(Code))}, + {reason, list_to_binary(rabbit_misc:format("~p~n", [Reason]))}]}, + {mochijson2:encode(Json), ReqState}. + +maybe_log(_Req, {error, {exit, normal, _Stack}}) -> + %% webmachine_request did an exit(normal), so suppress this + %% message. This usually happens when a chunked upload is + %% interrupted by network failure. + ok; +maybe_log(Req, Reason) -> + {Path, _} = Req:path(), + error_logger:error_msg("webmachine error: path=~p~n~p~n", [Path, Reason]). diff --git a/deps/rabbitmq_web_dispatch/src/rabbitmq_web_dispatch.app.src b/deps/rabbitmq_web_dispatch/src/rabbitmq_web_dispatch.app.src new file mode 100644 index 0000000..0e06ccc --- /dev/null +++ b/deps/rabbitmq_web_dispatch/src/rabbitmq_web_dispatch.app.src @@ -0,0 +1,8 @@ +{application, rabbitmq_web_dispatch, + [{description, "RabbitMQ Web Dispatcher"}, + {vsn, "3.6.6"}, + {modules, []}, + {registered, []}, + {mod, {rabbit_web_dispatch_app, []}}, + {env, []}, + {applications, [kernel, stdlib, rabbit_common, rabbit, mochiweb, webmachine]}]}. diff --git a/rabbitmq-server/deps/rabbitmq_web_mqtt/CODE_OF_CONDUCT.md b/deps/rabbitmq_web_stomp/CODE_OF_CONDUCT.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_mqtt/CODE_OF_CONDUCT.md rename to deps/rabbitmq_web_stomp/CODE_OF_CONDUCT.md diff --git a/rabbitmq-server/deps/rabbitmq_web_mqtt_examples/CONTRIBUTING.md b/deps/rabbitmq_web_stomp/CONTRIBUTING.md similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_mqtt_examples/CONTRIBUTING.md rename to deps/rabbitmq_web_stomp/CONTRIBUTING.md diff --git a/rabbitmq-server/deps/rabbitmq_web_mqtt/LICENSE b/deps/rabbitmq_web_stomp/LICENSE similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_mqtt/LICENSE rename to deps/rabbitmq_web_stomp/LICENSE diff --git a/rabbitmq-server/deps/rabbitmq_web_mqtt_examples/LICENSE-MPL-RabbitMQ b/deps/rabbitmq_web_stomp/LICENSE-MPL-RabbitMQ similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_mqtt_examples/LICENSE-MPL-RabbitMQ rename to deps/rabbitmq_web_stomp/LICENSE-MPL-RabbitMQ diff --git a/rabbitmq-server/deps/rabbitmq_web_stomp/Makefile b/deps/rabbitmq_web_stomp/Makefile similarity index 68% rename from rabbitmq-server/deps/rabbitmq_web_stomp/Makefile rename to deps/rabbitmq_web_stomp/Makefile index 3f2af7a..f14154e 100644 --- a/rabbitmq-server/deps/rabbitmq_web_stomp/Makefile +++ b/deps/rabbitmq_web_stomp/Makefile @@ -1,26 +1,9 @@ PROJECT = rabbitmq_web_stomp -PROJECT_DESCRIPTION = Rabbit WEB-STOMP - WebSockets to Stomp adapter -PROJECT_MOD = rabbit_ws_app - -define PROJECT_ENV -[ - {port, 15674}, - {tcp_config, []}, - {num_tcp_acceptors, 10}, - {ssl_config, []}, - {num_ssl_acceptors, 1}, - {cowboy_opts, []}, - {sockjs_opts, []}, - {ws_frame, text}, - {use_http_auth, false} - ] -endef DEPS = cowboy sockjs rabbit_common rabbit rabbitmq_stomp -TEST_DEPS = rabbitmq_ct_helpers rabbitmq_ct_client_helpers +TEST_DEPS = rabbitmq_ct_helpers dep_cowboy_commit = 1.0.3 -DEP_EARLY_PLUGINS = rabbit_common/mk/rabbitmq-early-plugin.mk DEP_PLUGINS = rabbit_common/mk/rabbitmq-plugin.mk # FIXME: Use erlang.mk patched for RabbitMQ, while waiting for PRs to be diff --git a/deps/rabbitmq_web_stomp/README.md b/deps/rabbitmq_web_stomp/README.md new file mode 100644 index 0000000..0d37e73 --- /dev/null +++ b/deps/rabbitmq_web_stomp/README.md @@ -0,0 +1,45 @@ +RabbitMQ Web STOMP plugin +========================= + +This project is a simple bridge between "RabbitMQ-stomp" plugin and +SockJS. + +Once started the plugin opens a SockJS endpoint on prefix "/stomp" on +port 15674, for example a valid SockJS endpoint url may look like: +"http://127.0.0.1:15674/stomp". + +Once the server is started you should be able to establish a SockJS +connection to this url. You will be able to communicate using the +usual STOMP protocol over it. For example, a page using Jeff Mesnil's +"stomp-websocket" project and SockJS may look like this: + + + + + + + + +

    SockJS-erlang Echo example

    + + + +
    + + diff --git a/deps/sockjs/examples/echo_authen_callback.html b/deps/sockjs/examples/echo_authen_callback.html new file mode 100644 index 0000000..b5718cf --- /dev/null +++ b/deps/sockjs/examples/echo_authen_callback.html @@ -0,0 +1,72 @@ + + + + + + +

    SockJS-erlang Echo example

    +
    + +
    +
    + + diff --git a/deps/sockjs/examples/multiplex/cowboy_multiplex.erl b/deps/sockjs/examples/multiplex/cowboy_multiplex.erl new file mode 100755 index 0000000..e0b8b42 --- /dev/null +++ b/deps/sockjs/examples/multiplex/cowboy_multiplex.erl @@ -0,0 +1,87 @@ +#!/usr/bin/env escript +%%! -smp disable +A1 +K true -pa ebin -env ERL_LIBS deps -input +-module(cowboy_multiplex). +-mode(compile). + +-export([main/1]). + +%% Cowboy callbacks +-export([init/3, handle/2, terminate/3]). + +main(_) -> + Port = 8081, + ok = application:start(xmerl), + ok = application:start(sockjs), + ok = application:start(ranch), + ok = application:start(crypto), + ok = application:start(cowlib), + ok = application:start(cowboy), + + MultiplexState = sockjs_multiplex:init_state( + [{"ann", fun service_ann/3, []}, + {"bob", fun service_bob/3, []}, + {"carl", fun service_carl/3, []}]), + + SockjsState = sockjs_handler:init_state( + <<"/multiplex">>, sockjs_multiplex, MultiplexState, []), + + VhostRoutes = [{<<"/multiplex/[...]">>, sockjs_cowboy_handler, SockjsState}, + {'_', ?MODULE, []}], + Routes = [{'_', VhostRoutes}], % any vhost + Dispatch = cowboy_router:compile(Routes), + + io:format(" [*] Running at http://localhost:~p~n", [Port]), + cowboy:start_http(http, 100, + [{port, Port}], + [{env, [{dispatch, Dispatch}]}]), + receive + _ -> ok + end. + +%% -------------------------------------------------------------------------- + +init({_Any, http}, Req, []) -> + {ok, Req, []}. + +handle(Req, State) -> + {Path, Req1} = cowboy_req:path(Req), + {ok, Req2} = case Path of + <<"/">> -> + {ok, Data} = file:read_file("./examples/multiplex/index.html"), + cowboy_req:reply(200, [{<<"Content-Type">>, "text/html"}], + Data, Req1); + _ -> + cowboy_req:reply(404, [], + <<"404 - Nothing here\n">>, Req1) + end, + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. + +%% -------------------------------------------------------------------------- + +service_ann(Conn, init, State) -> + sockjs:send("Ann says hi!", Conn), + {ok, State}; +service_ann(Conn, {recv, Data}, State) -> + sockjs:send(["Ann nods: ", Data], Conn), + {ok, State}; +service_ann(_Conn, closed, State) -> + {ok, State}. + +service_bob(Conn, init, State) -> + sockjs:send("Bob doesn't agree.", Conn), + {ok, State}; +service_bob(Conn, {recv, Data}, State) -> + sockjs:send(["Bob says no to: ", Data], Conn), + {ok, State}; +service_bob(_Conn, closed, State) -> + {ok, State}. + +service_carl(Conn, init, State) -> + sockjs:send("Carl says goodbye!", Conn), + sockjs:close(Conn), + {ok, State}; +service_carl(_Conn, _, State) -> + {ok, State}. diff --git a/deps/sockjs/examples/multiplex/cowboy_multiplex_authen_callback.erl b/deps/sockjs/examples/multiplex/cowboy_multiplex_authen_callback.erl new file mode 100755 index 0000000..625a605 --- /dev/null +++ b/deps/sockjs/examples/multiplex/cowboy_multiplex_authen_callback.erl @@ -0,0 +1,107 @@ +#!/usr/bin/env escript +%%! -smp disable +A1 +K true -pa ebin -env ERL_LIBS deps -input +-module(cowboy_multiplex). +-mode(compile). + +-export([main/1]). + +%% Cowboy callbacks +-export([init/3, handle/2, terminate/3]). + +main(_) -> + Port = 8081, + ok = application:start(xmerl), + ok = application:start(sockjs), + ok = application:start(ranch), + ok = application:start(crypto), + ok = application:start(cowlib), + ok = application:start(cowboy), + + MultiplexState = sockjs_multiplex:init_state( + [{"ann", fun service_ann/3, []}, + {"bob", fun service_bob/3, []}, + {"carl", fun service_carl/3, []}], + {fun authen/3, [{state, []}]}), + + SockjsState = sockjs_handler:init_state( + <<"/multiplex">>, sockjs_multiplex, MultiplexState, []), + + VhostRoutes = [{<<"/multiplex/[...]">>, sockjs_cowboy_handler, SockjsState}, + {'_', ?MODULE, []}], + Routes = [{'_', VhostRoutes}], % any vhost + Dispatch = cowboy_router:compile(Routes), + + io:format(" [*] Running at http://localhost:~p~n", [Port]), + cowboy:start_http(http, 100, + [{port, Port}], + [{env, [{dispatch, Dispatch}]}]), + receive + _ -> ok + end. + +%% -------------------------------------------------------------------------- + +init({_Any, http}, Req, []) -> + {ok, Req, []}. + +handle(Req, State) -> + {Path, Req1} = cowboy_req:path(Req), + {ok, Req2} = case Path of + <<"/">> -> + {ok, Data} = file:read_file("./examples/multiplex/index_authen_callback.html"), + cowboy_req:reply(200, [{<<"Content-Type">>, "text/html"}], + Data, Req1); + _ -> + cowboy_req:reply(404, [], + <<"404 - Nothing here\n">>, Req1) + end, + {ok, Req2, State}. + +terminate(_Reason, _Req, _State) -> + ok. + +%% -------------------------------------------------------------------------- + +authen(Conn, init, Extra) -> + {ok, TRef} = timer:apply_after(5000, sockjs, close, [Conn]), + {ok, [TRef | Extra]}; +authen(Conn, {recv, Data}, [TRef | Extra] = State) -> + case Data of + <<"auth">> -> + sockjs:send(<<"Authenticate successfully!">>, Conn), + timer:cancel(TRef), + {success, [{user_id, element(3, erlang:now())} | Extra]}; + _Else -> + {ok, State} + end; +authen(_Conn, closed, [TRef | Extra]) -> + timer:cancel(TRef), + {ok, Extra}. + +service_ann(Conn, init, State) -> + sockjs:send("Ann says hi!", Conn), + {ok, State}; +service_ann(Conn, {recv, Data}, State) -> + {user_id, UserId} = lists:keyfind(user_id, 1, State), + sockjs:send(["Ann nods: ", Data, " from ", erlang:integer_to_binary(UserId)], Conn), + {ok, State}; +service_ann(_Conn, closed, State) -> + {ok, State}. + +service_bob(Conn, init, State) -> + sockjs:send("Bob doesn't agree.", Conn), + {ok, State}; +service_bob(Conn, {recv, Data}, State) -> + {user_id, UserId} = lists:keyfind(user_id, 1, State), + sockjs:send(["Bob says no to: ", Data, " from ", erlang:integer_to_binary(UserId)], + Conn), + {ok, State}; +service_bob(_Conn, closed, State) -> + {ok, State}. + +service_carl(Conn, init, State) -> + sockjs:send("Carl says goodbye!", Conn), + sockjs:close(Conn), + {ok, State}; +service_carl(_Conn, _, State) -> + {ok, State}. diff --git a/deps/sockjs/examples/multiplex/index.html b/deps/sockjs/examples/multiplex/index.html new file mode 100644 index 0000000..3353e6f --- /dev/null +++ b/deps/sockjs/examples/multiplex/index.html @@ -0,0 +1,96 @@ + + + + + + + +

    SockJS Multiplex example

    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + + + diff --git a/deps/sockjs/examples/multiplex/index_authen_callback.html b/deps/sockjs/examples/multiplex/index_authen_callback.html new file mode 100644 index 0000000..ee6d8aa --- /dev/null +++ b/deps/sockjs/examples/multiplex/index_authen_callback.html @@ -0,0 +1,109 @@ + + + + + + + +

    SockJS Multiplex example

    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + +
    +
    +
    +
    + + + diff --git a/rabbitmq-server/deps/sockjs/rebar b/deps/sockjs/rebar similarity index 100% rename from rabbitmq-server/deps/sockjs/rebar rename to deps/sockjs/rebar diff --git a/rabbitmq-server/deps/sockjs/rebar.config b/deps/sockjs/rebar.config similarity index 100% rename from rabbitmq-server/deps/sockjs/rebar.config rename to deps/sockjs/rebar.config diff --git a/rabbitmq-server/deps/sockjs/src/mochijson2_fork.erl b/deps/sockjs/src/mochijson2_fork.erl similarity index 89% rename from rabbitmq-server/deps/sockjs/src/mochijson2_fork.erl rename to deps/sockjs/src/mochijson2_fork.erl index f13f94e..a088d9d 100644 --- a/rabbitmq-server/deps/sockjs/src/mochijson2_fork.erl +++ b/deps/sockjs/src/mochijson2_fork.erl @@ -216,18 +216,22 @@ json_encode_proplist(Props, State) -> lists:reverse([$\} | Acc1]). json_encode_string(A, State) when is_atom(A) -> - B = iolist_to_binary(atom_to_list(A)), - json_encode_string(B, State); + L = atom_to_list(A), + case json_string_is_safe(L) of + true -> + [?Q, L, ?Q]; + false -> + json_encode_string_unicode(xmerl_ucs:from_utf8(L), State, [?Q]) + end; json_encode_string(B, State) when is_binary(B) -> case json_bin_is_safe(B) of true -> - <>; + [?Q, B, ?Q]; false -> - json_encode_string_unicode_bin(B, State) + json_encode_string_unicode(xmerl_ucs:from_utf8(B), State, [?Q]) end; json_encode_string(I, _State) when is_integer(I) -> - B = integer_to_binary(I), - <>; + [?Q, integer_to_list(I), ?Q]; json_encode_string(L, State) when is_list(L) -> case json_string_is_safe(L) of true -> @@ -286,84 +290,6 @@ json_bin_is_safe(<>) -> json_bin_is_safe(Rest) end. -%% encode utf8 string with binraies -json_encode_string_unicode_bin(Bin, State) when is_binary(Bin) -> - Body = json_encode_string_unicode_bin(Bin, State, <<"">>, <<"">>), - <>. - -json_encode_string_unicode_bin(<<"">>, State, Acc, Buff) -> - Buff0 = json_encode_string_unicode_bin_check(Buff, State), - <>; - -json_encode_string_unicode_bin(<>, State, Acc, Buff) -> - {Acc1, Buff1} = case C of - $\" -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $"); - $\\ -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $\\); - $\b -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $b); - $\f -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $f); - $\n -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $n); - $\r -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $r); - $\t -> json_encode_string_unicode_bin_simple(State, Acc, Buff, $t); - - C when C >= 0, C < $\s -> - Buff0 = json_encode_string_unicode_bin_check(Buff, State), - CEsc = unihex_bin(C), - {<>, - <<"">>}; - C when C < 2#01111111 -> - Buff0 = json_encode_string_unicode_bin_check(Buff, State), - {<>, - <<"">>}; - C when C < 2#11000000, byte_size(Buff) >= 1 -> - {Acc, - <>}; - C when C >= 2#11000000 -> - Buff0 = json_encode_string_unicode_bin_check(Buff, State), - {<>, - <>}; - _ -> exit({json_encode, {bad_char, [Buff]}}) - end, - json_encode_string_unicode_bin(Rest, State, Acc1, Buff1). - -json_encode_string_unicode_bin_simple(State, Acc, Buff, Repl) -> - Buff0 = json_encode_string_unicode_bin_check(Buff, State), - {<>, - <<"">>}. - -json_encode_string_unicode_bin_check(Buff, _State) when byte_size(Buff) < 1 -> - Buff; -json_encode_string_unicode_bin_check(Buff, State) -> - UniCode = case Buff of - <> when P0==2#110, P1==2#10 -> - D0*16#40 + D1; - <> when P0==2#1110, P1==2#10 -> - D0*16#1000 + D1*16#40 + D2; - <> when P0==2#11110, P1==2#10 -> - D0*16#040000 + D1*16#1000 + D2*16#40 + D3; - _ -> exit({json_encode, {bad_unicode_char, [Buff]}}) - end, - case State#encoder.utf8 of - false -> unihex_bin(UniCode); - true -> Buff - end. - - -unihex_bin(C) when C < 16#10000 -> - Digits = << <> || <> <= <> >>, - <<$\\, $u, Digits/binary>>; -unihex_bin(C) when C =< 16#10FFFF -> - N = C - 16#10000, - S1 = unihex_bin(16#d800 bor ((N bsr 10) band 16#3ff)), - S2 = unihex_bin(16#dc00 bor (N band 16#3ff)), - <>. - -% json_encode_string_unicode([], _State, Acc) -> lists:reverse([$\" | Acc]); json_encode_string_unicode([C | Cs], State, Acc) -> @@ -803,13 +729,13 @@ e2j_test_vec(utf8) -> %% test utf8 encoding encoder_utf8_test() -> %% safe conversion case (default) - Ans1 = iolist_to_binary([34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34]), - Ans1 = encode(<<1,"\321\202\320\265\321\201\321\202">>), + [34,"\\u0001","\\u0442","\\u0435","\\u0441","\\u0442",34] = + encode(<<1,"\321\202\320\265\321\201\321\202">>), %% raw utf8 output (optional) - Enc = mochijson2_fork:encoder([{utf8, true}]), - Ans2 = iolist_to_binary([34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34]), - Ans2 = Enc(<<1,"\321\202\320\265\321\201\321\202">>). + Enc = mochijson2:encoder([{utf8, true}]), + [34,"\\u0001",[209,130],[208,181],[209,129],[209,130],34] = + Enc(<<1,"\321\202\320\265\321\201\321\202">>). input_validation_test() -> Good = [ diff --git a/rabbitmq-server/deps/sockjs/src/mochinum_fork.erl b/deps/sockjs/src/mochinum_fork.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/mochinum_fork.erl rename to deps/sockjs/src/mochinum_fork.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs.app.src b/deps/sockjs/src/sockjs.app.src similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs.app.src rename to deps/sockjs/src/sockjs.app.src diff --git a/rabbitmq-server/deps/sockjs/src/sockjs.erl b/deps/sockjs/src/sockjs.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs.erl rename to deps/sockjs/src/sockjs.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_action.erl b/deps/sockjs/src/sockjs_action.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_action.erl rename to deps/sockjs/src/sockjs_action.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_app.erl b/deps/sockjs/src/sockjs_app.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_app.erl rename to deps/sockjs/src/sockjs_app.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_cowboy_handler.erl b/deps/sockjs/src/sockjs_cowboy_handler.erl similarity index 92% rename from rabbitmq-server/deps/sockjs/src/sockjs_cowboy_handler.erl rename to deps/sockjs/src/sockjs_cowboy_handler.erl index de5c549..c66c9d4 100644 --- a/rabbitmq-server/deps/sockjs/src/sockjs_cowboy_handler.erl +++ b/deps/sockjs/src/sockjs_cowboy_handler.erl @@ -33,15 +33,16 @@ terminate(_Reason, _Req, _Service) -> websocket_init(_TransportName, Req, Service = #service{logger = Logger, subproto_pref = SubProtocolPref}) -> - Req3 = case cowboy_req:header(<<"sec-websocket-protocol">>, Req) of + Req3 = case cowboy_req:header(<<"Sec-Websocket-Protocol">>, Req) of {undefined, Req1} -> Req1; {SubProtocols, Req1} -> SelectedSubProtocol = choose_subprotocol_bin(SubProtocols, SubProtocolPref), - cowboy_req:set_resp_header( - <<"sec-websocket-protocol">>, - SelectedSubProtocol, Req1) + {ok, Req2} = cowboy_req:set_resp_header( + <<"Sec-Websocket-Protocol">>, + SelectedSubProtocol, Req1), + Req2 end, Req4 = Logger(Service, {cowboy, Req3}, websocket), diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_filters.erl b/deps/sockjs/src/sockjs_filters.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_filters.erl rename to deps/sockjs/src/sockjs_filters.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_handler.erl b/deps/sockjs/src/sockjs_handler.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_handler.erl rename to deps/sockjs/src/sockjs_handler.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_http.erl b/deps/sockjs/src/sockjs_http.erl similarity index 87% rename from rabbitmq-server/deps/sockjs/src/sockjs_http.erl rename to deps/sockjs/src/sockjs_http.erl index f5afec8..828247d 100644 --- a/rabbitmq-server/deps/sockjs/src/sockjs_http.erl +++ b/deps/sockjs/src/sockjs_http.erl @@ -23,7 +23,14 @@ method_atom(<<"POST">>) -> 'POST'; method_atom(<<"DELETE">>) -> 'DELETE'; method_atom(<<"OPTIONS">>) -> 'OPTIONS'; method_atom(<<"PATCH">>) -> 'PATCH'; -method_atom(<<"HEAD">>) -> 'HEAD'. +method_atom(<<"HEAD">>) -> 'HEAD'; +method_atom('GET') -> 'GET'; +method_atom('PUT') -> 'PUT'; +method_atom('POST') -> 'POST'; +method_atom('DELETE') -> 'DELETE'; +method_atom('OPTIONS') -> 'OPTIONS'; +method_atom('PATCH') -> 'PATCH'; +method_atom('HEAD') -> 'HEAD'. -spec body(req()) -> {binary(), req()}. body({cowboy, Req}) -> {ok, Body, Req1} = cowboy_req:body(Req), @@ -49,11 +56,16 @@ body_qs2({cowboy, Req}) -> end. -spec header(atom(), req()) -> {nonempty_string() | undefined, req()}. -header(K, {cowboy, Req0})-> - {V, Req} = cowboy_req:header(atom_to_binary(K, latin1), Req0), +header(K, {cowboy, Req})-> + {H, Req2} = cowboy_req:header(K, Req), + {V, Req3} = case H of + undefined -> + cowboy_req:header(atom_to_binary(K, utf8), Req2); + _ -> {H, Req2} + end, case V of - undefined -> {undefined, {cowboy, Req}}; - _ -> {binary_to_list(V), {cowboy, Req}} + undefined -> {undefined, {cowboy, Req3}}; + _ -> {binary_to_list(V), {cowboy, Req3}} end. -spec jsessionid(req()) -> {nonempty_string() | undefined, req()}. diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_internal.hrl b/deps/sockjs/src/sockjs_internal.hrl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_internal.hrl rename to deps/sockjs/src/sockjs_internal.hrl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_json.erl b/deps/sockjs/src/sockjs_json.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_json.erl rename to deps/sockjs/src/sockjs_json.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_multiplex.erl b/deps/sockjs/src/sockjs_multiplex.erl similarity index 98% rename from rabbitmq-server/deps/sockjs/src/sockjs_multiplex.erl rename to deps/sockjs/src/sockjs_multiplex.erl index f6831d9..3922e8c 100644 --- a/rabbitmq-server/deps/sockjs/src/sockjs_multiplex.erl +++ b/deps/sockjs/src/sockjs_multiplex.erl @@ -105,7 +105,7 @@ action(Conn, {Type, Topic, Payload}, Service, Channels, Extra) -> orddict:store(Topic, emit(init, Channel), Channels); {"uns", true} -> Channel = orddict:fetch(Topic, Channels), - _ = emit(closed, Channel), + emit(closed, Channel), orddict:erase(Topic, Channels); {"msg", true} -> Channel = orddict:fetch(Topic, Channels), @@ -129,7 +129,9 @@ emit(What, Channel = #service{callback = Callback, split(Char, Str, Limit) when Limit > 0 -> Acc = split(Char, Str, Limit, []), - lists:reverse(Acc). + lists:reverse(Acc); +split(_Char, Str, 0) -> + [Str]. split(_Char, Str, 1, Acc) -> [Str | Acc]; diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_multiplex_channel.erl b/deps/sockjs/src/sockjs_multiplex_channel.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_multiplex_channel.erl rename to deps/sockjs/src/sockjs_multiplex_channel.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_service.erl b/deps/sockjs/src/sockjs_service.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_service.erl rename to deps/sockjs/src/sockjs_service.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_session.erl b/deps/sockjs/src/sockjs_session.erl similarity index 98% rename from rabbitmq-server/deps/sockjs/src/sockjs_session.erl rename to deps/sockjs/src/sockjs_session.erl index b7ae74d..d2d5d8b 100644 --- a/rabbitmq-server/deps/sockjs/src/sockjs_session.erl +++ b/deps/sockjs/src/sockjs_session.erl @@ -17,7 +17,7 @@ -export_type([conn/0]). --ifdef(use_old_builtin_types). +-ifdef(pre17_type_specs). -define(QUEUE_TYPE, queue()). -else. -define(QUEUE_TYPE, queue:queue()). @@ -25,13 +25,13 @@ -record(session, {id :: session(), outbound_queue = queue:new() :: ?QUEUE_TYPE, - response_pid :: pid() | undefined, - disconnect_tref :: reference() | undefined, + response_pid :: pid(), + disconnect_tref :: reference(), disconnect_delay = 5000 :: non_neg_integer(), - heartbeat_tref :: reference() | triggered | undefined, + heartbeat_tref :: reference() | triggered, heartbeat_delay = 25000 :: non_neg_integer(), ready_state = connecting :: connecting | open | closed, - close_msg :: {non_neg_integer(), string()} | undefined, + close_msg :: {non_neg_integer(), string()}, callback, state, handle :: handle() diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_session_sup.erl b/deps/sockjs/src/sockjs_session_sup.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_session_sup.erl rename to deps/sockjs/src/sockjs_session_sup.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_util.erl b/deps/sockjs/src/sockjs_util.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_util.erl rename to deps/sockjs/src/sockjs_util.erl diff --git a/rabbitmq-server/deps/sockjs/src/sockjs_ws_handler.erl b/deps/sockjs/src/sockjs_ws_handler.erl similarity index 100% rename from rabbitmq-server/deps/sockjs/src/sockjs_ws_handler.erl rename to deps/sockjs/src/sockjs_ws_handler.erl diff --git a/deps/webmachine/Emakefile b/deps/webmachine/Emakefile new file mode 100644 index 0000000..7ee92ef --- /dev/null +++ b/deps/webmachine/Emakefile @@ -0,0 +1,6 @@ +% -*- mode: erlang -*- +{["src/*"], + [{i, "include"}, + {outdir, "ebin"}, + debug_info] +}. diff --git a/deps/webmachine/LICENSE b/deps/webmachine/LICENSE new file mode 100644 index 0000000..e454a52 --- /dev/null +++ b/deps/webmachine/LICENSE @@ -0,0 +1,178 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/deps/webmachine/Makefile b/deps/webmachine/Makefile new file mode 100644 index 0000000..a3ed568 --- /dev/null +++ b/deps/webmachine/Makefile @@ -0,0 +1,25 @@ +IGNORE_DEPS += edown eper eunit_formatters meck node_package rebar_lock_deps_plugin rebar_vsn_plugin reltool_util +C_SRC_DIR = /path/do/not/exist +C_SRC_TYPE = rebar +DRV_CFLAGS = -fPIC +export DRV_CFLAGS +ERLANG_ARCH = 64 +export ERLANG_ARCH +ERLC_OPTS = +debug_info +export ERLC_OPTS +ERLC_OPTS += -Dold_hash=1 + +DEPS += mochiweb +dep_mochiweb = git git://github.com/rabbitmq/mochiweb 845428379ed8b58eadc49aba26838d86ea809663 +COMPILE_FIRST += + + +rebar_dep: preprocess pre-deps deps pre-app app + +preprocess:: + +pre-deps:: + +pre-app:: + +include ../../erlang.mk \ No newline at end of file diff --git a/deps/webmachine/Makefile.orig.mk b/deps/webmachine/Makefile.orig.mk new file mode 100644 index 0000000..e9de516 --- /dev/null +++ b/deps/webmachine/Makefile.orig.mk @@ -0,0 +1,24 @@ +ERL ?= erl +APP := webmachine + +.PHONY: deps + +all: deps + @(./rebar compile) + +deps: + @(./rebar get-deps) + +clean: + @(./rebar clean) + +distclean: clean + @(./rebar delete-deps) + +edoc: + @$(ERL) -noshell -run edoc_run application '$(APP)' '"."' '[{preprocess, true},{includes, ["."]}]' + +test: all + @(./rebar skip_deps=true eunit) + + diff --git a/deps/webmachine/README.org b/deps/webmachine/README.org new file mode 100644 index 0000000..73b985d --- /dev/null +++ b/deps/webmachine/README.org @@ -0,0 +1,66 @@ +* webmachine +** Overview + +[[http://travis-ci.org/basho/webmachine][Travis-CI]] :: [[https://secure.travis-ci.org/basho/webmachine.png]] + +Webmachine is an application layer that adds HTTP semantic awareness +on top of the excellent bit-pushing and HTTP syntax-management +provided by mochiweb, and provides a simple and clean way to connect +that to your application's behavior. + +More information is available [[http://webmachine.basho.com/][here]]. + +** Quick Start +A shell script is provided in the =webmachine= repository to help +users quickly and easily create a new =webmachine= application. + +#+BEGIN_SRC shell +git clone git://github.com/basho/webmachine.git +cd webmachine +./scripts/new_webmachine.sh mydemo +#+END_SRC + +A destination path can also be passed to the =new_webmachine.sh= +script. + +#+BEGIN_SRC shell +./scripts/new_webmachine.sh mydemo ~/webmachine_applications +#+END_SRC + +Once a new application has been created it can be built and started. + +#+BEGIN_SRC shell +cd mydemo +make +./start.sh +#+END_SRC + +The application will be available at [[http://localhost:8000]]. + +To learn more continue reading [[http://webmachine.basho.com/][here]]. + +** Contributing + We encourage contributions to =webmachine= from the community. + + 1) Fork the =webmachine= repository on [[https://github.com/basho/webmachine][Github]]. + 2) Clone your fork or add the remote if you already have a clone of + the repository. +#+BEGIN_SRC shell +git clone git@github.com:yourusername/webmachine.git +# or +git remote add mine git@github.com:yourusername/webmachine.git +#+END_SRC + 3) Create a topic branch for your change. +#+BEGIN_SRC shell +git checkout -b some-topic-branch +#+END_SRC + 4) Make your change and commit. Use a clear and descriptive commit + message, spanning multiple lines if detailed explanation is + needed. + 5) Push to your fork of the repository and then send a pull-request + through Github. +#+BEGIN_SRC shell +git push mine some-topic-branch +#+END_SRC + 6) A Basho engineer or community maintainer will review your patch + and merge it into the main repository or send you feedback. diff --git a/deps/webmachine/THANKS b/deps/webmachine/THANKS new file mode 100644 index 0000000..e3a10ba --- /dev/null +++ b/deps/webmachine/THANKS @@ -0,0 +1,21 @@ +The following people have contributed to Webmachine: + +Andy Gross +Justin Sheehy +John Muellerleile +Robert Ahrens +Jeremy Latt +Bryan Fink +Ryan Tilder +Taavi Talvik +Marc Worrell +Seth Falcon +Tuncer Ayaz +Martin Scholl +Paul Mineiro +Dave Smith +Arjan Scherpenisse +Benjamin Black +Anthony Molinaro +Phil Pirozhkov +Rusty Klophaus \ No newline at end of file diff --git a/deps/webmachine/demo/Makefile b/deps/webmachine/demo/Makefile new file mode 100644 index 0000000..e134e6a --- /dev/null +++ b/deps/webmachine/demo/Makefile @@ -0,0 +1,19 @@ +ERL ?= erl +APP := webmachine_demo + +.PHONY: deps + +all: deps + @../rebar compile + +deps: + @../rebar get-deps + +clean: + @../rebar clean + +distclean: clean + @../rebar delete-deps + +docs: + @erl -noshell -run edoc_run application '$(APP)' '"."' '[]' diff --git a/deps/webmachine/demo/README b/deps/webmachine/demo/README new file mode 100644 index 0000000..cc5ab25 --- /dev/null +++ b/deps/webmachine/demo/README @@ -0,0 +1,43 @@ +Project Skeleton for the webmachine_demo app. + +You should find in this directory: + +README : this file +Makefile : simple make commands +rebar : the Rebar build tool for Erlang applications +rebar.config : configuration for Rebar +start.sh : simple startup script for running webmachine_demo +/ebin + /webmachine_demo.app : the Erlang app specification +/src + /webmachine_demo_app.erl : base module for the Erlang application + /webmachine_demo_sup.erl : OTP supervisor for the application + /webmachine_demo_resource.erl : a simple example Webmachine resource +/priv + /dispatch.conf : the Webmachine URL-dispatching table + /www : a convenient place to put your static web content + +You probably want to do one of a couple of things at this point: + +0. Build the skeleton application: + $ make + - or - + $ ./rebar compile + +1. Start up the skeleton application: + $ ./start.sh + +2. Test the basic application: + Visit http://localhost:8000/demo + +3. Change the basic application: + edit src/webmachine_demo_resource.erl + +4. Test the filesystem resource: + $ mkdir /tmp/fs + $ echo "Hello World." > /tmp/fs/demo.txt + Visit http://localhost:8000/fs/demo.txt + +5. Add some new resources: + edit src/YOUR_NEW_RESOURCE.erl + edit priv/dispatch.conf diff --git a/deps/webmachine/demo/priv/dispatch.conf b/deps/webmachine/demo/priv/dispatch.conf new file mode 100644 index 0000000..587ea31 --- /dev/null +++ b/deps/webmachine/demo/priv/dispatch.conf @@ -0,0 +1,3 @@ +%%-*- mode: erlang -*- +{["demo", '*'], webmachine_demo_resource, []}. +{["fs", '*'], webmachine_demo_fs_resource, [{root, "/tmp/fs"}]}. diff --git a/deps/webmachine/demo/rebar.config b/deps/webmachine/demo/rebar.config new file mode 100644 index 0000000..d245b80 --- /dev/null +++ b/deps/webmachine/demo/rebar.config @@ -0,0 +1,3 @@ +%%-*- mode: erlang -*- + +{deps, [{webmachine, "1.10.*", {git, "git://github.com/basho/webmachine", "HEAD"}}]}. diff --git a/deps/webmachine/demo/src/webmachine_demo.app.src b/deps/webmachine/demo/src/webmachine_demo.app.src new file mode 100644 index 0000000..a18addd --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo.app.src @@ -0,0 +1,17 @@ +%%-*- mode: erlang -*- +{application, webmachine_demo, + [ + {description, "demo"}, + {vsn, "1"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib, + crypto, + mochiweb, + webmachine + ]}, + {mod, { webmachine_demo_app, []}}, + {env, []} + ]}. diff --git a/deps/webmachine/demo/src/webmachine_demo.erl b/deps/webmachine/demo/src/webmachine_demo.erl new file mode 100644 index 0000000..1431fb9 --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo.erl @@ -0,0 +1,42 @@ +-module(webmachine_demo). +-author('Andy Gross '). +-author('Justin Sheehy '). +-export([start/0, start_link/0, stop/0]). + +ensure_started(App) -> + case application:start(App) of + ok -> + ok; + {error, {already_started, App}} -> + ok + end. + +%% @spec start_link() -> {ok,Pid::pid()} +%% @doc Starts the app for inclusion in a supervisor tree +start_link() -> + ensure_started(crypto), + ensure_started(mochiweb), + application:set_env(webmachine, webmachine_logger_module, + webmachine_logger), + ensure_started(webmachine), + webmachine_demo_sup:start_link(). + +%% @spec start() -> ok +%% @doc Start the webmachine_demo server. +start() -> + ensure_started(inets), + ensure_started(crypto), + ensure_started(mochiweb), + application:set_env(webmachine, webmachine_logger_module, + webmachine_logger), + ensure_started(webmachine), + application:start(webmachine_demo). + +%% @spec stop() -> ok +%% @doc Stop the webmachine_demo server. +stop() -> + Res = application:stop(webmachine_demo), + application:stop(webmachine), + application:stop(mochiweb), + application:stop(crypto), + Res. diff --git a/deps/webmachine/demo/src/webmachine_demo_app.erl b/deps/webmachine/demo/src/webmachine_demo_app.erl new file mode 100644 index 0000000..f36f22e --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo_app.erl @@ -0,0 +1,20 @@ +%% @author Andy Gross +%% @author Justin Sheehy + +%% @doc Callbacks for the webmachine_demo application. + +-module(webmachine_demo_app). + +-behaviour(application). +-export([start/2,stop/1]). + + +%% @spec start(_Type, _StartArgs) -> ServerRet +%% @doc application start callback for webmachine_demo. +start(_Type, _StartArgs) -> + webmachine_demo_sup:start_link(). + +%% @spec stop(_State) -> ServerRet +%% @doc application stop callback for webmachine_demo. +stop(_State) -> + ok. diff --git a/deps/webmachine/demo/src/webmachine_demo_fs_resource.erl b/deps/webmachine/demo/src/webmachine_demo_fs_resource.erl new file mode 100644 index 0000000..9488268 --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo_fs_resource.erl @@ -0,0 +1,159 @@ +%% @author Bryan Fink +%% @author Andy Gross +%% @author Justin Sheehy +%% @copyright 2008-2009 Basho Technologies, Inc. + +-module(webmachine_demo_fs_resource). +-export([init/1]). +-export([allowed_methods/2, + resource_exists/2, + last_modified/2, + content_types_provided/2, + content_types_accepted/2, + delete_resource/2, + post_is_create/2, + create_path/2, + provide_content/2, + accept_content/2, + generate_etag/2]). + +-record(context, {root,response_body=undefined,metadata=[]}). + +-include_lib("kernel/include/file.hrl"). +-include_lib("webmachine/include/webmachine.hrl"). + +init(ConfigProps) -> + {root, Root} = proplists:lookup(root, ConfigProps), + {ok, #context{root=Root}}. + +allowed_methods(ReqData, Context) -> + {['HEAD', 'GET', 'PUT', 'DELETE', 'POST'], ReqData, Context}. + +file_path(_Context, []) -> + false; +file_path(Context, Name) -> + RelName = case hd(Name) of + "/" -> tl(Name); + _ -> Name + end, + filename:join([Context#context.root, RelName]). + +file_exists(Context, Name) -> + NamePath = file_path(Context, Name), + case filelib:is_regular(NamePath) of + true -> + {true, NamePath}; + false -> + false + end. + +resource_exists(ReqData, Context) -> + Path = wrq:disp_path(ReqData), + case file_exists(Context, Path) of + {true, _} -> + {true, ReqData, Context}; + _ -> + case Path of + "p" -> {true, ReqData, Context}; + _ -> {false, ReqData, Context} + end + end. + +maybe_fetch_object(Context, Path) -> + % if returns {true, NewContext} then NewContext has response_body + case Context#context.response_body of + undefined -> + case file_exists(Context, Path) of + {true, FullPath} -> + {ok, Value} = file:read_file(FullPath), + {true, Context#context{response_body=Value}}; + false -> + {false, Context} + end; + _Body -> + {true, Context} + end. + +content_types_provided(ReqData, Context) -> + CT = webmachine_util:guess_mime(wrq:disp_path(ReqData)), + {[{CT, provide_content}], ReqData, + Context#context{metadata=[{'content-type', CT}|Context#context.metadata]}}. + +content_types_accepted(ReqData, Context) -> + CT = case wrq:get_req_header("content-type", ReqData) of + undefined -> "application/octet-stream"; + X -> X + end, + {MT, _Params} = webmachine_util:media_type_to_detail(CT), + {[{MT, accept_content}], ReqData, + Context#context{metadata=[{'content-type', MT}|Context#context.metadata]}}. + +accept_content(ReqData, Context) -> + Path = wrq:disp_path(ReqData), + FP = file_path(Context, Path), + ok = filelib:ensure_dir(FP), + ReqData1 = case file_exists(Context, Path) of + {true, _} -> + ReqData; + _ -> + LOC = "http://" ++ + wrq:get_req_header("host", ReqData) ++ + "/fs/" ++ Path, + wrq:set_resp_header("Location", LOC, ReqData) + end, + Value = wrq:req_body(ReqData1), + case file:write_file(FP, Value) of + ok -> + {true, wrq:set_resp_body(Value, ReqData1), Context}; + Err -> + {{error, Err}, ReqData1, Context} + end. + +post_is_create(ReqData, Context) -> + {true, ReqData, Context}. + +create_path(ReqData, Context) -> + case wrq:get_req_header("slug", ReqData) of + undefined -> {undefined, ReqData, Context}; + Slug -> + case file_exists(Context, Slug) of + {true, _} -> {undefined, ReqData, Context}; + _ -> {Slug, ReqData, Context} + end + end. + +delete_resource(ReqData, Context) -> + case file:delete(file_path( + Context, wrq:disp_path(ReqData))) of + ok -> {true, ReqData, Context}; + _ -> {false, ReqData, Context} + end. + +provide_content(ReqData, Context) -> + case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of + {true, NewContext} -> + Body = NewContext#context.response_body, + {Body, ReqData, Context}; + {false, NewContext} -> + {error, ReqData, NewContext} + end. + +last_modified(ReqData, Context) -> + {true, FullPath} = file_exists(Context, + wrq:disp_path(ReqData)), + LMod = filelib:last_modified(FullPath), + {LMod, ReqData, Context#context{metadata=[{'last-modified', + httpd_util:rfc1123_date(LMod)}|Context#context.metadata]}}. + +hash_body(Body) -> mochihex:to_hex(binary_to_list(crypto:sha(Body))). + +generate_etag(ReqData, Context) -> + case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of + {true, BodyContext} -> + ETag = hash_body(BodyContext#context.response_body), + {ETag, ReqData, + BodyContext#context{metadata=[{etag,ETag}| + BodyContext#context.metadata]}}; + _ -> + {undefined, ReqData, Context} + end. diff --git a/deps/webmachine/demo/src/webmachine_demo_resource.erl b/deps/webmachine/demo/src/webmachine_demo_resource.erl new file mode 100644 index 0000000..797ab78 --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo_resource.erl @@ -0,0 +1,51 @@ +%% @author Justin Sheehy +%% @copyright 2007-2009 Basho Technologies, Inc. All Rights Reserved. +%% @doc Example webmachine_resource. + +-module(webmachine_demo_resource). +-author('Justin Sheehy '). +-export([init/1, to_html/2, to_text/2, content_types_provided/2, + is_authorized/2, generate_etag/2, expires/2, last_modified/2]). + +-include_lib("webmachine/include/webmachine.hrl"). + +init([]) -> {ok, undefined}. + +content_types_provided(ReqData, Context) -> + {[{"text/html", to_html},{"text/plain",to_text}], ReqData, Context}. + +to_text(ReqData, Context) -> + Path = wrq:disp_path(ReqData), + Body = io_lib:format("Hello ~s from webmachine.~n", [Path]), + {Body, ReqData, Context}. + +to_html(ReqData, Context) -> + {Body, _RD, Ctx2} = to_text(ReqData, Context), + HBody = io_lib:format("~s~n", + [erlang:iolist_to_binary(Body)]), + {HBody, ReqData, Ctx2}. + +is_authorized(ReqData, Context) -> + case wrq:disp_path(ReqData) of + "authdemo" -> + case wrq:get_req_header("authorization", ReqData) of + "Basic "++Base64 -> + Str = base64:mime_decode_to_string(Base64), + case string:tokens(Str, ":") of + ["authdemo", "demo1"] -> + {true, ReqData, Context}; + _ -> + {"Basic realm=webmachine", ReqData, Context} + end; + _ -> + {"Basic realm=webmachine", ReqData, Context} + end; + _ -> {true, ReqData, Context} + end. + +expires(ReqData, Context) -> {{{2021,1,1},{0,0,0}}, ReqData, Context}. + +last_modified(ReqData, Context) -> + {calendar:now_to_universal_time(os:timestamp()), ReqData, Context}. + +generate_etag(ReqData, Context) -> {wrq:raw_path(ReqData), ReqData, Context}. diff --git a/deps/webmachine/demo/src/webmachine_demo_sup.erl b/deps/webmachine/demo/src/webmachine_demo_sup.erl new file mode 100644 index 0000000..ea4532c --- /dev/null +++ b/deps/webmachine/demo/src/webmachine_demo_sup.erl @@ -0,0 +1,56 @@ +%% @author author +%% @copyright YYYY author. + +%% @doc Supervisor for the webmachine_demo application. + +-module(webmachine_demo_sup). + +-behaviour(supervisor). + +%% External exports +-export([start_link/0, upgrade/0]). + +%% supervisor callbacks +-export([init/1]). + +%% @spec start_link() -> ServerRet +%% @doc API for starting the supervisor. +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% @spec upgrade() -> ok +%% @doc Add processes if necessary. +upgrade() -> + {ok, {_, Specs}} = init([]), + + Old = sets:from_list( + [Name || {Name, _, _, _} <- supervisor:which_children(?MODULE)]), + New = sets:from_list([Name || {Name, _, _, _, _, _} <- Specs]), + Kill = sets:subtract(Old, New), + + sets:fold(fun (Id, ok) -> + supervisor:terminate_child(?MODULE, Id), + supervisor:delete_child(?MODULE, Id), + ok + end, ok, Kill), + + [supervisor:start_child(?MODULE, Spec) || Spec <- Specs], + ok. + +%% @spec init([]) -> SupervisorTree +%% @doc supervisor callback. +init([]) -> + Ip = case os:getenv("WEBMACHINE_IP") of false -> "0.0.0.0"; Any -> Any end, + {ok, Dispatch} = file:consult(filename:join( + [filename:dirname(code:which(?MODULE)), + "..", "priv", "dispatch.conf"])), + WebConfig = [ + {ip, Ip}, + {port, 8000}, + {log_dir, "priv/log"}, + {dispatch, Dispatch}], + Web = {webmachine_mochiweb, + {webmachine_mochiweb, start, [WebConfig]}, + permanent, 5000, worker, dynamic}, + Processes = [Web], + {ok, { {one_for_one, 10, 10}, Processes} }. diff --git a/deps/webmachine/demo/start.sh b/deps/webmachine/demo/start.sh new file mode 100755 index 0000000..8a234ab --- /dev/null +++ b/deps/webmachine/demo/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd `dirname $0` +exec erl -pa $PWD/ebin $PWD/deps/*/ebin -boot start_sasl -s reloader -s webmachine_demo diff --git a/deps/webmachine/docs/http-headers-status-v3.png b/deps/webmachine/docs/http-headers-status-v3.png new file mode 100644 index 0000000000000000000000000000000000000000..231316066863c9f786ab5f251c37cd0a17eb3940 GIT binary patch literal 412634 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�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%0DmpBq7QjI}GjyIj+2wiWH9$xL zSZIw5n;08_nbu0&TH4#P@MV#|{Ag2SBW%FydDIo|r=(8twZpGn=gcqdl|E2YfKlf- zBpnM{(62v=BptkSLDN1==s*q9A0>VOYbQ?EZm8E=&Fh(Z6UifZnEm!(iV`-2a@PHt zUxoR1{KBiSCn`0sG8X;c3zmn?wdGG)w-(N3`+&UBQtZmXltLdOo6^JN3PDZ|CA>t5 z$!^izY592Sfnq$5;cBzA7oQ3U-$(NYyz)ifPxmhO)zr&2!iIOSc^vU8esLBtRlFL(=!REb_e||t z6xe6_;!0hOpxvcC6$x{sm*S~f$G-bUdfkY7dl`p3l$7uHDR8mHz+6f1?Ch)P`1{i* z{EPFXh}D0$4_I;-D_hA0lhhvI;wn9=o%9x9AN)PtM{Rb;?C* zoAe0lVkp|(oaf^H6Mm5-=zEn**op)gW_FOYYqrrn z3iZ*9lX_%nPhpeC*_WRa8#qqka$l7`Qeh@#D~eO%nrIma>aTYNl-yPkJXZ#1ET}ri z7x)nQnMI}%jz2Wp7E@SR_%yI*k7t~fBI|CqTY@3h6Qel3kp1UGPyd3n5jZ`ft$$8K zd?GuBdDI0q)uu#Ux7WRbL6yQtQS{PiPc-eLoYk`G3iqbzF+u0aQDlBogYcSN7=3G7 zhV!ditLW?6O5$IJ8U%TBhiWU*IIRUmBwo-P%LimTjBD~zZ9w~OU2WwKv-x6bJo2RK z5bX<_2*nbCbVhUg0Q!L@!>C|_)jFm@M~^~oRlkz{iG zU-GP-!cwX&sX# zLH#Q(1X$Y;*I?@dk38QUz0FToS8)|hRlfE(BukT2U^QWGuK(W3I%x0eod#wbml?i| zCOxk0gHNhtd4@F`N%SJ4EBDLxAA}$oIP*O%KSGqeDw%=Ea0(EALRYacNgO?S+pQlvh6!cG)8xY;x~rOV4ZHpUyz^P2)YKw9s;(B9FN-SlbkMU$*JdZJXdJ4 zG<#Xk#93T!t&tK)vDu4gEeSP2v5ek(aq&o^arn89Ib{)3)e6QlnPtaE(u7E%Z#1JX z-hWNsdYH>L07FkIk8$jmQ)#L2X&YJZt$(x8XqGX9hQ|*;iN!6Jb?V#duCkRSsx$>5 z+{1@2YE6aEl2(V08qDc)Iu%gtUP2yf9f-vRg9~LVHDe0qR}CgtzU6?9*yWd?i3FAd z=4u&M$%?;-2ZyJP>gGWJ0Cx7xENRyl8I)YsReWZIfQ4)jPU*wr1K+}~NJb#UhsuQf z9v$R5_j%>Jk%UKuyQfk6(yuSv2XL`)Z9Jp|&u8UvPF>h@@yT~n8pb01%hTN%jkf*Q zxtxeP0aGFkz7xG?4=nEIKL#)NtYu03GW&T$`tz)bUOUKAl_n(B6kmZE>+j;NhqmOUp;rxBL=jd@jlFT{Vg1>*W< + {pong, ReqData, State}. + + diff --git a/rabbitmq-server/deps/rabbitmq_web_dispatch/src/webmachine_logger.hrl b/deps/webmachine/include/webmachine_logger.hrl similarity index 100% rename from rabbitmq-server/deps/rabbitmq_web_dispatch/src/webmachine_logger.hrl rename to deps/webmachine/include/webmachine_logger.hrl diff --git a/deps/webmachine/include/wm_reqdata.hrl b/deps/webmachine/include/wm_reqdata.hrl new file mode 100644 index 0000000..e82bcbc --- /dev/null +++ b/deps/webmachine/include/wm_reqdata.hrl @@ -0,0 +1,8 @@ +-record(wm_reqdata, {method, scheme, version, peer, wm_state, + disp_path, path, raw_path, path_info, path_tokens, + app_root,response_code,max_recv_body, max_recv_hunk, + req_cookie, req_qs, req_headers, req_body, + resp_redirect, resp_headers, resp_body, resp_range, + host_tokens, port, notes + }). + diff --git a/deps/webmachine/include/wm_reqstate.hrl b/deps/webmachine/include/wm_reqstate.hrl new file mode 100644 index 0000000..a72a574 --- /dev/null +++ b/deps/webmachine/include/wm_reqstate.hrl @@ -0,0 +1,10 @@ +-record(wm_reqstate, {socket=undefined, + metadata=orddict:new(), + range=undefined, + peer=undefined, + reqdata=undefined, + bodyfetch=undefined, + reqbody=undefined, + log_data=undefined + }). + diff --git a/deps/webmachine/include/wm_resource.hrl b/deps/webmachine/include/wm_resource.hrl new file mode 100644 index 0000000..588405d --- /dev/null +++ b/deps/webmachine/include/wm_resource.hrl @@ -0,0 +1 @@ +-record(wm_resource, {module, modstate, modexports, trace}). diff --git a/deps/webmachine/priv/templates/Makefile b/deps/webmachine/priv/templates/Makefile new file mode 100644 index 0000000..812f23b --- /dev/null +++ b/deps/webmachine/priv/templates/Makefile @@ -0,0 +1,19 @@ +ERL ?= erl +APP := {{appid}} + +.PHONY: deps + +all: deps + @./rebar compile + +deps: + @./rebar get-deps + +clean: + @./rebar clean + +distclean: clean + @./rebar delete-deps + +docs: + @erl -noshell -run edoc_run application '$(APP)' '"."' '[]' diff --git a/deps/webmachine/priv/templates/README b/deps/webmachine/priv/templates/README new file mode 100644 index 0000000..36f5591 --- /dev/null +++ b/deps/webmachine/priv/templates/README @@ -0,0 +1,35 @@ +Project Skeleton for the {{appid}} app. + +You should find in this directory: + +README : this file +Makefile : simple make commands +rebar : the Rebar build tool for Erlang applications +rebar.config : configuration for Rebar +start.sh : simple startup script for running {{appid}} +/ebin + /{{appid}}.app : the Erlang app specification +/src + /{{appid}}_app.erl : base module for the Erlang application + /{{appid}}_sup.erl : OTP supervisor for the application + /{{appid}}_resource.erl : a simple example Webmachine resource +/priv + /dispatch.conf : the Webmachine URL-dispatching table + /www : a convenient place to put your static web content + +You probably want to do one of a couple of things at this point: + +0. Build the skeleton application: + $ make + - or - + $ ./rebar compile + +1. Start up the skeleton application: + $ ./start.sh + +2. Change the basic application: + edit src/{{appid}}_resource.erl + +3. Add some new resources: + edit src/YOUR_NEW_RESOURCE.erl + edit priv/dispatch.conf diff --git a/deps/webmachine/priv/templates/priv/dispatch.conf b/deps/webmachine/priv/templates/priv/dispatch.conf new file mode 100644 index 0000000..fdc5f0e --- /dev/null +++ b/deps/webmachine/priv/templates/priv/dispatch.conf @@ -0,0 +1,2 @@ +%%-*- mode: erlang -*- +{[], {{appid}}_resource, []}. diff --git a/deps/webmachine/priv/templates/rebar.config b/deps/webmachine/priv/templates/rebar.config new file mode 100644 index 0000000..d245b80 --- /dev/null +++ b/deps/webmachine/priv/templates/rebar.config @@ -0,0 +1,3 @@ +%%-*- mode: erlang -*- + +{deps, [{webmachine, "1.10.*", {git, "git://github.com/basho/webmachine", "HEAD"}}]}. diff --git a/deps/webmachine/priv/templates/src/wmskel.app.src b/deps/webmachine/priv/templates/src/wmskel.app.src new file mode 100644 index 0000000..449abf6 --- /dev/null +++ b/deps/webmachine/priv/templates/src/wmskel.app.src @@ -0,0 +1,18 @@ +%%-*- mode: erlang -*- +{application, {{appid}}, + [ + {description, "{{appid}}"}, + {vsn, "1"}, + {modules, []}, + {registered, []}, + {applications, [ + kernel, + stdlib, + inets, + crypto, + mochiweb, + webmachine + ]}, + {mod, { {{appid}}_app, []}}, + {env, []} + ]}. diff --git a/deps/webmachine/priv/templates/src/wmskel.erl b/deps/webmachine/priv/templates/src/wmskel.erl new file mode 100644 index 0000000..2ef035e --- /dev/null +++ b/deps/webmachine/priv/templates/src/wmskel.erl @@ -0,0 +1,48 @@ +%% @author author +%% @copyright YYYY author. + +%% @doc {{appid}} startup code + +-module({{appid}}). +-author('author '). +-export([start/0, start_link/0, stop/0]). + +ensure_started(App) -> + case application:start(App) of + ok -> + ok; + {error, {already_started, App}} -> + ok + end. + +%% @spec start_link() -> {ok,Pid::pid()} +%% @doc Starts the app for inclusion in a supervisor tree +start_link() -> + ensure_started(inets), + ensure_started(crypto), + ensure_started(mochiweb), + application:set_env(webmachine, webmachine_logger_module, + webmachine_logger), + ensure_started(webmachine), + {{appid}}_sup:start_link(). + +%% @spec start() -> ok +%% @doc Start the {{appid}} server. +start() -> + ensure_started(inets), + ensure_started(crypto), + ensure_started(mochiweb), + application:set_env(webmachine, webmachine_logger_module, + webmachine_logger), + ensure_started(webmachine), + application:start({{appid}}). + +%% @spec stop() -> ok +%% @doc Stop the {{appid}} server. +stop() -> + Res = application:stop({{appid}}), + application:stop(webmachine), + application:stop(mochiweb), + application:stop(crypto), + application:stop(inets), + Res. diff --git a/deps/webmachine/priv/templates/src/wmskel_app.erl b/deps/webmachine/priv/templates/src/wmskel_app.erl new file mode 100644 index 0000000..61f6b73 --- /dev/null +++ b/deps/webmachine/priv/templates/src/wmskel_app.erl @@ -0,0 +1,21 @@ +%% @author author +%% @copyright YYYY author. + +%% @doc Callbacks for the {{appid}} application. + +-module({{appid}}_app). +-author('author '). + +-behaviour(application). +-export([start/2,stop/1]). + + +%% @spec start(_Type, _StartArgs) -> ServerRet +%% @doc application start callback for {{appid}}. +start(_Type, _StartArgs) -> + {{appid}}_sup:start_link(). + +%% @spec stop(_State) -> ServerRet +%% @doc application stop callback for {{appid}}. +stop(_State) -> + ok. diff --git a/deps/webmachine/priv/templates/src/wmskel_resource.erl b/deps/webmachine/priv/templates/src/wmskel_resource.erl new file mode 100644 index 0000000..5112803 --- /dev/null +++ b/deps/webmachine/priv/templates/src/wmskel_resource.erl @@ -0,0 +1,13 @@ +%% @author author +%% @copyright YYYY author. +%% @doc Example webmachine_resource. + +-module({{appid}}_resource). +-export([init/1, to_html/2]). + +-include_lib("webmachine/include/webmachine.hrl"). + +init([]) -> {ok, undefined}. + +to_html(ReqData, State) -> + {"Hello, new world", ReqData, State}. diff --git a/deps/webmachine/priv/templates/src/wmskel_sup.erl b/deps/webmachine/priv/templates/src/wmskel_sup.erl new file mode 100644 index 0000000..53e11f4 --- /dev/null +++ b/deps/webmachine/priv/templates/src/wmskel_sup.erl @@ -0,0 +1,72 @@ +%% @author author +%% @copyright YYYY author. + +%% @doc Supervisor for the {{appid}} application. + +-module({{appid}}_sup). +-author('author '). + +-behaviour(supervisor). + +%% External exports +-export([start_link/0, upgrade/0]). + +%% supervisor callbacks +-export([init/1]). + +%% @spec start_link() -> ServerRet +%% @doc API for starting the supervisor. +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% @spec upgrade() -> ok +%% @doc Add processes if necessary. +upgrade() -> + {ok, {_, Specs}} = init([]), + + Old = sets:from_list( + [Name || {Name, _, _, _} <- supervisor:which_children(?MODULE)]), + New = sets:from_list([Name || {Name, _, _, _, _, _} <- Specs]), + Kill = sets:subtract(Old, New), + + sets:fold(fun (Id, ok) -> + supervisor:terminate_child(?MODULE, Id), + supervisor:delete_child(?MODULE, Id), + ok + end, ok, Kill), + + [supervisor:start_child(?MODULE, Spec) || Spec <- Specs], + ok. + +%% @spec init([]) -> SupervisorTree +%% @doc supervisor callback. +init([]) -> + Ip = case os:getenv("WEBMACHINE_IP") of false -> "0.0.0.0"; Any -> Any end, + {ok, App} = application:get_application(?MODULE), + {ok, Dispatch} = file:consult(filename:join([priv_dir(App), + "dispatch.conf"])), + Port = case os:getenv("WEBMACHINE_PORT") of + false -> 8000; + AnyPort -> AnyPort + end, + WebConfig = [ + {ip, Ip}, + {port, Port}, + {log_dir, "priv/log"}, + {dispatch, Dispatch}], + Web = {webmachine_mochiweb, + {webmachine_mochiweb, start, [WebConfig]}, + permanent, 5000, worker, [mochiweb_socket_server]}, + Processes = [Web], + {ok, { {one_for_one, 10, 10}, Processes} }. + +%% +%% @doc return the priv dir +priv_dir(Mod) -> + case code:priv_dir(Mod) of + {error, bad_name} -> + Ebin = filename:dirname(code:which(Mod)), + filename:join(filename:dirname(Ebin), "priv"); + PrivDir -> + PrivDir + end. diff --git a/deps/webmachine/priv/templates/start.sh b/deps/webmachine/priv/templates/start.sh new file mode 100644 index 0000000..0a7ff56 --- /dev/null +++ b/deps/webmachine/priv/templates/start.sh @@ -0,0 +1,3 @@ +#!/bin/sh +cd `dirname $0` +exec erl -pa $PWD/ebin $PWD/deps/*/ebin -boot start_sasl -s reloader -s {{appid}} diff --git a/deps/webmachine/priv/templates/wmskel.template b/deps/webmachine/priv/templates/wmskel.template new file mode 100644 index 0000000..c150ac8 --- /dev/null +++ b/deps/webmachine/priv/templates/wmskel.template @@ -0,0 +1,35 @@ +%%-*- mode: erlang -*- +%% Basic Webmachine application skeleton + +%% Variables: +%% appid: name of the application to build +%% default = "wmskel" +%% webmachine: path to webmachine from this template +%% default = "../.." +%% prefix: path where the application should be created +%% default = "." +{variables, [{appid, "wmskel"}, + {webmachine, "../.."}, + {prefix, "."}]}. + +%% main project files +{template, "README", "{{prefix}}/README"}. +{template, "Makefile", "{{prefix}}/Makefile"}. +{template, "rebar.config", "{{prefix}}/rebar.config"}. +{file, "{{webmachine}}/rebar", "{{prefix}}/rebar"}. +{chmod, 8#744, "{{prefix}}/rebar"}. +{template, "start.sh", "{{prefix}}/start.sh"}. +{chmod, 8#744, "{{prefix}}/start.sh"}. + +{template, "src/wmskel.app.src", "{{prefix}}/src/{{appid}}.app.src"}. + +{template, "src/wmskel.erl", "{{prefix}}/src/{{appid}}.erl"}. +{template, "src/wmskel_app.erl", "{{prefix}}/src/{{appid}}_app.erl"}. +{template, "src/wmskel_sup.erl", "{{prefix}}/src/{{appid}}_sup.erl"}. +{template, "src/wmskel_resource.erl", "{{prefix}}/src/{{appid}}_resource.erl"}. + +{template, "priv/dispatch.conf", "{{prefix}}/priv/dispatch.conf"}. +{dir, "{{prefix}}/priv/www"}. + +%% dependencies +{dir, "{{prefix}}/deps"}. diff --git a/deps/webmachine/priv/trace/http-headers-status-v3.png b/deps/webmachine/priv/trace/http-headers-status-v3.png new file mode 100644 index 0000000000000000000000000000000000000000..231316066863c9f786ab5f251c37cd0a17eb3940 GIT binary patch literal 412634 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�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
    5aa6Xx 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%0DmpBq7QjI}GjyIj+2wiWH9$xL zSZIw5n;08_nbu0&TH4#P@MV#|{Ag2SBW%FydDIo|r=(8twZpGn=gcqdl|E2YfKlf- zBpnM{(62v=BptkSLDN1==s*q9A0>VOYbQ?EZm8E=&Fh(Z6UifZnEm!(iV`-2a@PHt zUxoR1{KBiSCn`0sG8X;c3zmn?wdGG)w-(N3`+&UBQtZmXltLdOo6^JN3PDZ|CA>t5 z$!^izY592Sfnq$5;cBzA7oQ3U-$(NYyz)ifPxmhO)zr&2!iIOSc^vU8esLBtRlFL(=!REb_e||t z6xe6_;!0hOpxvcC6$x{sm*S~f$G-bUdfkY7dl`p3l$7uHDR8mHz+6f1?Ch)P`1{i* z{EPFXh}D0$4_I;-D_hA0lhhvI;wn9=o%9x9AN)PtM{Rb;?C* zoAe0lVkp|(oaf^H6Mm5-=zEn**op)gW_FOYYqrrn z3iZ*9lX_%nPhpeC*_WRa8#qqka$l7`Qeh@#D~eO%nrIma>aTYNl-yPkJXZ#1ET}ri z7x)nQnMI}%jz2Wp7E@SR_%yI*k7t~fBI|CqTY@3h6Qel3kp1UGPyd3n5jZ`ft$$8K zd?GuBdDI0q)uu#Ux7WRbL6yQtQS{PiPc-eLoYk`G3iqbzF+u0aQDlBogYcSN7=3G7 zhV!ditLW?6O5$IJ8U%TBhiWU*IIRUmBwo-P%LimTjBD~zZ9w~OU2WwKv-x6bJo2RK z5bX<_2*nbCbVhUg0Q!L@!>C|_)jFm@M~^~oRlkz{iG zU-GP-!cwX&sX# zLH#Q(1X$Y;*I?@dk38QUz0FToS8)|hRlfE(BukT2U^QWGuK(W3I%x0eod#wbml?i| zCOxk0gHNhtd4@F`N%SJ4EBDLxAA}$oIP*O%KSGqeDw%=Ea0(EALRYacNgO?S+pQlvh6!cG)8xY;x~rOV4ZHpUyz^P2)YKw9s;(B9FN-SlbkMU$*JdZJXdJ4 zG<#Xk#93T!t&tK)vDu4gEeSP2v5ek(aq&o^arn89Ib{)3)e6QlnPtaE(u7E%Z#1JX z-hWNsdYH>L07FkIk8$jmQ)#L2X&YJZt$(x8XqGX9hQ|*;iN!6Jb?V#duCkRSsx$>5 z+{1@2YE6aEl2(V08qDc)Iu%gtUP2yf9f-vRg9~LVHDe0qR}CgtzU6?9*yWd?i3FAd z=4u&M$%?;-2ZyJP>gGWJ0Cx7xENRyl8I)YsReWZIfQ4)jPU*wr1K+}~NJb#UhsuQf z9v$R5_j%>Jk%UKuyQfk6(yuSv2XL`)Z9Jp|&u8UvPF>h@@yT~n8pb01%hTN%jkf*Q zxtxeP0aGFkz7xG?4=nEIKL#)NtYu03GW&T$`tz)bUOUKAl_n(B6kmZE>+j;NhqmOUp;rxBL=jd@jlFT{Vg1>*W<'; + } + return prev; +}; + +function drawTrace() { + drawDecision(trace[0]); + for (var i = 1; i < trace.length; i++) { + drawPath(trace[i].path); + drawDecision(trace[i]); + } + + drawPath(response.path); + drawResponse(); +}; + +function drawResponse() { + if (response.type == 'normal') { + var context = canvas.getContext('2d'); + context.strokeStyle=HIGHLIGHT; + context.lineWidth=4; + + context.beginPath(); + context.rect(response.x-(response.width/2), + response.y-19, + response.width, + 38); + context.stroke(); + } else { + var context = canvas.getContext('2d'); + context.strokeStyle='#ff0000'; + context.lineWidth=4; + + context.beginPath(); + context.arc(response.x, response.y, 19, + 0, 2*3.14159, false); + context.stroke(); + + } +}; + +function drawDecision(dec) { + var context = canvas.getContext('2d'); + + if (dec.previewCalls == '') + context.strokeStyle=REGULAR; + else + context.strokeStyle=HIGHLIGHT; + context.lineWidth=4; + + context.beginPath(); + context.moveTo(dec.x, dec.y-19); + context.lineTo(dec.x+19, dec.y); + context.lineTo(dec.x, dec.y+19); + context.lineTo(dec.x-19, dec.y); + context.closePath(); + context.stroke(); +}; + +function drawPath(path) { + var context = canvas.getContext('2d'); + context.strokeStyle=REGULAR; + context.lineWidth=4; + + context.beginPath(); + context.moveTo(path[0].x1, path[0].y1); + for (var p = 0; p < path.length; p++) { + context.lineTo(path[p].x2, path[p].y2); + } + context.stroke(); +}; + +function getSeg(p1, p2, last) { + var seg = { + x1:cols[p1[0]], + y1:rows[p1.slice(1)] + }; + if (ends[p2]) { + seg.x2 = cols[ends[p2].col]; + seg.y2 = rows[ends[p2].row]; + } else { + seg.x2 = cols[p2[0]]; + seg.y2 = rows[p2.slice(1)]; + } + + if (seg.x1 == seg.x2) { + if (seg.y1 < seg.y2) { + seg.y1 = seg.y1+19; + if (last) seg.y2 = seg.y2-19; + } else { + seg.y1 = seg.y1-19; + if (last) seg.y2 = seg.y2+19; + } + } else { + //assume seg.y1 == seg.y2 + if (seg.x1 < seg.x2) { + seg.x1 = seg.x1+19; + if (last) seg.x2 = seg.x2-(ends[p2] ? (ends[p2].width/2) : 19); + } else { + seg.x1 = seg.x1-19; + if (last) seg.x2 = seg.x2+(ends[p2] ? (ends[p2].width/2) : 19); + } + } + return seg; +}; + +function traceDecision(name) { + for (var i = trace.length-1; i >= 0; i--) + if (trace[i].d == name) return trace[i]; +}; + +var detailPanels = {}; +function initDetailPanels() { + var windowWidth = document.getElementById('sizetest').clientWidth; + var infoPanel = document.getElementById('infopanel'); + var panelWidth = windowWidth-infoPanel.offsetLeft; + + var panels = { + 'request': document.getElementById('requestdetail'), + 'response': document.getElementById('responsedetail'), + 'decision': document.getElementById('decisiondetail') + }; + + var tabs = { + 'request': document.getElementById('requesttab'), + 'response': document.getElementById('responsetab'), + 'decision': document.getElementById('decisiontab') + }; + + var decisionId = document.getElementById('decisionid'); + var decisionCalls = document.getElementById('decisioncalls'); + var callInput = document.getElementById('callinput'); + var callOutput = document.getElementById('calloutput'); + + var lastUsedPanelWidth = windowWidth-infoPanel.offsetLeft; + + var setPanelWidth = function(width) { + infoPanel.style.left = (windowWidth-width)+'px'; + canvas.style.marginRight = (width+20)+'px'; + panelWidth = width; + }; + setPanelWidth(panelWidth); + + var ensureVisible = function() { + if (windowWidth-infoPanel.offsetLeft < 10) + setPanelWidth(lastUsedPanelWidth); + }; + + var decChoices = ''; + for (var i = 0; i < trace.length; i++) { + decChoices += ''; + } + decisionId.innerHTML = decChoices; + decisionId.selectedIndex = -1; + + decisionId.onchange = function() { + detailPanels.setDecision(traceDecision(decisionId.value)); + } + + detailPanels.setDecision = function(dec) { + decisionId.value = dec.d; + + var calls = []; + for (var i = 0; i < dec.calls.length; i++) { + calls.push(''); + } + decisionCalls.innerHTML = calls.join(''); + decisionCalls.selectedIndex = 0; + + decisionCalls.onchange(); + }; + + detailPanels.show = function(name) { + for (p in panels) { + if (p == name) { + panels[p].style.display = 'block'; + tabs[p].className = 'selectedtab'; + } + else { + panels[p].style.display = 'none'; + tabs[p].className = ''; + } + } + ensureVisible(); + }; + + detailPanels.hide = function() { + setPanelWidth(0); + } + + decisionCalls.onchange = function() { + var val = decisionCalls.value; + if (val) { + var dec = traceDecision(val.substring(0, val.indexOf('-'))); + var call = dec.calls[parseInt(val.substring(val.indexOf('-')+1, val.length))]; + + if (call.output != "wmtrace_not_exported") { + callInput.style.color='#000000'; + callInput.innerHTML = call.input; + if (call.output != null) { + callOutput.style.color = '#000000'; + callOutput.innerHTML = call.output; + } else { + callOutput.style.color = '#ff0000'; + callOutput.textContent = 'Error: '+call.module+':'+call['function']+' never returned'; + } + } else { + callInput.style.color='#999999'; + callInput.textContent = call.module+':'+call['function']+' was not exported'; + callOutput.textContent = ''; + } + } else { + callInput.textContent = ''; + callOutput.textContent = ''; + } + }; + + var headersList = function(headers) { + var h = ''; + for (n in headers) h += '
  • '+n+': '+headers[n]; + return h; + }; + + document.getElementById('requestmethod').innerHTML = request.method; + document.getElementById('requestpath').innerHTML = request.path; + document.getElementById('requestheaders').innerHTML = headersList(request.headers); + document.getElementById('requestbody').innerHTML = request.body; + + document.getElementById('responsecode').innerHTML = response.code; + document.getElementById('responseheaders').innerHTML = headersList(response.headers); + document.getElementById('responsebody').innerHTML = response.body; + + + var infoControls = document.getElementById('infocontrols'); + var md = false; + var dragged = false; + var msoff = 0; + infoControls.onmousedown = function(ev) { + md = true; + dragged = false; + msoff = ev.clientX-infoPanel.offsetLeft; + }; + + infoControls.onclick = function(ev) { + if (dragged) { + lastUsedPanelWidth = panelWidth; + } + else if (panelWidth < 10) { + switch(ev.target.id) { + case 'requesttab': detailPanels.show('request'); break; + case 'responsetab': detailPanels.show('response'); break; + case 'decisiontab': detailPanels.show('decision'); break; + default: ensureVisible(); + } + } else { + var name = 'none'; + switch(ev.target.id) { + case 'requesttab': name = 'request'; break; + case 'responsetab': name = 'response'; break; + case 'decisiontab': name = 'decision'; break; + } + + if (panels[name] && panels[name].style.display != 'block') + detailPanels.show(name); + else + detailPanels.hide(); + } + + return false; + }; + + document.onmousemove = function(ev) { + if (md) { + dragged = true; + panelWidth = windowWidth-(ev.clientX-msoff); + if (panelWidth < 0) { + panelWidth = 0; + infoPanel.style.left = windowWidth+"px"; + } + else if (panelWidth > windowWidth-21) { + panelWidth = windowWidth-21; + infoPanel.style.left = '21px'; + } + else + infoPanel.style.left = (ev.clientX-msoff)+"px"; + + canvas.style.marginRight = panelWidth+20+"px"; + return false; + } + }; + + document.onmouseup = function() { md = false; }; + + window.onresize = function() { + windowWidth = document.getElementById('sizetest').clientWidth; + infoPanel.style.left = windowWidth-panelWidth+'px'; + }; +}; + +window.onload = function() { + canvas = document.getElementById('v3map'); + + initDetailPanels(); + + var scale = 0.25; + var coy = canvas.offsetTop; + function findDecision(ev) { + var x = (ev.clientX+window.pageXOffset)/scale; + var y = (ev.clientY+window.pageYOffset-coy)/scale; + + for (var i = trace.length-1; i >= 0; i--) { + if (x >= trace[i].x-19 && x <= trace[i].x+19 && + y >= trace[i].y-19 && y <= trace[i].y+19) + return trace[i]; + } + }; + + var preview = document.getElementById('preview'); + var previewId = document.getElementById('previewid'); + var previewCalls = document.getElementById('previewcalls'); + function previewDecision(dec) { + preview.style.left = (dec.x*scale)+'px'; + preview.style.top = (dec.y*scale+coy+15)+'px'; + preview.style.display = 'block'; + previewId.textContent = dec.d; + + previewCalls.innerHTML = dec.previewCalls; + }; + + function overResponse(ev) { + var x = (ev.clientX+window.pageXOffset)/scale; + var y = (ev.clientY+window.pageYOffset-coy)/scale; + + return (x >= response.x-(response.width/2) + && x <= response.x+(response.width/2) + && y >= response.y-19 && y <= response.y+19); + }; + + decorateTrace(); + + var bg = new Image(3138, 2184); + + function drawMap() { + var ctx = canvas.getContext("2d"); + + ctx.save(); + ctx.scale(1/scale, 1/scale); + ctx.fillStyle = '#ffffff'; + ctx.fillRect(0, 0, 3138, 2184); + ctx.restore(); + + ctx.drawImage(bg, 0, 0); + drawTrace(); + }; + + bg.onload = function() { + canvas.getContext("2d").scale(scale, scale); + drawMap(scale); + + canvas.onmousemove = function(ev) { + if (findDecision(ev)) { + canvas.style.cursor = 'pointer'; + previewDecision(findDecision(ev)); + } + else { + preview.style.display = 'none'; + if (overResponse(ev)) + canvas.style.cursor = 'pointer'; + else + canvas.style.cursor = 'default'; + } + }; + + canvas.onclick = function(ev) { + var dec = findDecision(ev); + if (dec) { + detailPanels.setDecision(dec); + detailPanels.show('decision'); + } else if (overResponse(ev)) { + detailPanels.show('response'); + } + }; + + document.getElementById('zoomin').onclick = function() { + scale = scale*2; + canvas.getContext("2d").scale(2, 2); + drawMap(); + }; + + document.getElementById('zoomout').onclick = function() { + scale = scale/2; + canvas.getContext("2d").scale(0.5, 0.5); + drawMap(); + }; + }; + + bg.onerror = function() { + alert('Failed to load background image.'); + }; + + bg.src = 'static/map.png'; +}; diff --git a/deps/webmachine/priv/www/index.html b/deps/webmachine/priv/www/index.html new file mode 100644 index 0000000..e999208 --- /dev/null +++ b/deps/webmachine/priv/www/index.html @@ -0,0 +1,8 @@ + + +It Worked + + +Running. + + diff --git a/deps/webmachine/rebar b/deps/webmachine/rebar new file mode 100755 index 0000000000000000000000000000000000000000..7bdb274306991818770baacbec3a76beff5befe6 GIT binary patch literal 119212 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

    +hL3E4;MWk>7 zUyi!0d~(2tI)BGeq9c(&l}Nx;Xq})&X~Iv>5xGrgy9C<`ZzArlFwR;Za<`H6hG3tpF0^4;A3(%`C?_LP78%bRYCFL`W-AoS z-Lm>slDs}<6QKju!x(5vjo+=rfr7k-K0L9Z*$~UY#UHH*Ke1LP9ihIt^C$)o?d_km zm;&5db9BBG_~BCf$$6za+oda}wLMGrNaG+QAAWne26W0CcaG+tBtoVAf#V+3IiZE! z1ht62+@yO{3LP@{f}eJIeN31#XW3jdi_;Iz2v&*ZIS~aL2ZKmQGHY=~^|>AZi#@z> z^|ad1ribKCMvP+plaV=OxdIF3AOY|Qk!HHrgt#)@*lsZVXV5Bkz;?iUeF>0yM(+X9 zmvUOSz}~xATQ5QpuhpD5lzSw1Py94mUPb-`UPVkdRL%P5kW4{j$nLL zp^_kqFn+$x`cCO^6MK`zPd!9%Y?7tqLD5SeG|Dy5o@X4s27|oU2*;KMPsJS+o4n5r z9-~sy$86Z`O?t$l@IG#WyzX9&AqVi#npW0|{z2Ex3du-aXf!nO3&J8>HDC%OKs^{^ z-YBh(!DrXw*yzqB)UvsH7VnFMQA$-9lE$Ci1;jjjj8XF68so?tF;(tReT#5aH-fKt z0)91VEcxgANS7hfH+d?c5H83FoSQwd?GVm>V?;{{Vi{Q>y zpQ8X@9$KE-z@tEASWoa*w?Zm7WURCPKr65_!a7!7^N=t3TnCsBZ@;0gMOdf*9iRhw z#vS5-;S_1m=nuVh-S(E>Ir#&vzXO$Tl~ir$r^1?=@_n;b4FFlsYEq{O$bjbBF(WUw^9yWn;RG% z_{Z5Dyi{YSYkr%Z`0R3QJG`s>RJ+V*mgft3FOIh_&6Iax?R9wSF3oN$xAW;?Ye)U; z&d%c_IX?%t&to^f-s?)OO;oSV&d-;%cPV^sboQqEk!R1Gb$+%yT-W_)ePga_%{6ql z^TF3)YgY#jZ-&usDqMZ5OIIoF^pEkTK=b#EZ;ze&`7rM5bj{~Y&F^?=NlpxTR{8EQ z`_@AvIsf~!_H^tpe-V3Rb;nx>+SbF@pxwP=~{~=U)RGFaqnB`?`)-Qnj4|V^^a@r z`sdYlsm;eqq3dqvM+J6I^;4JA!IAIn#}oIqt(A9$ipB5H`{z{UE#Li&o~^qWWb}vL z*9PkBi;nj$d$lj>?ziycWp6#+*LgnjY3nH-hm*x(`3!i^FC}j#KVnHqHBQa5?ReBJ zY4Z-C6Y2Tt9lA$d=$)IK3o_p9Jj?!ll`%vwB8BLiZl2-+@~aDVa|8GDIs_6njh?7g z9qrB}9?|IMhUlG}xX1u|bbl)Ri*r+0b&3~QFdUchtpZvZ{x&ni-Qe8T*y??M92SX|_dq(dMe5-)=?6-F=%3 zId3BKq{^g0fAT^5zLAgRO@N1qO-k9f=b?p^B+gv}uh|A%QKt-RIq)W!3XS2G(D`2z1*-<}p zboeM*4!WJrU*P{lSg?w}W=Q|!g1`SRs{Z*f{|~}C+A#i4wLm8fTNR~;*)<{Er19E_ z?ApS2R9587g*|cGcw4R5)m7HeXtU;f5Q>XCy>$-{aWsy1L`-4ltBD3jL2@ zg=!%I*nt7YD){I!d-TCcN)M;M!xg7=N%y(`5qsq``cTMQg%Z zbvy)8kYXyHu>{azv)hHiT4}NFRFY#BZ`1g16Fk)GbN7f~)~pW=M4h%(ZYXuBVUXZ2 zHS)9`sOY1HGOj*OFxzMR4Q9Oh%%NALO~M}a8FZ@j($gD&guz!Y3^|9+$KTf&wgO4B zof#R(xW!e3+%7Xf|1=4^ZrLDMu?t`bQ|$`bKC|#}5fS0C8P*ogz{0(h{f;F#4f&vs z->iL=?l}!sk*>&<&A>Jy1R&$V2JWjgnl--LW0t?e@E;oQTBx+&u#gpFh>ie=U=mO$ z15!x}RZz?n5akVwFylv30ijI_QIcNa$X54?7M2uvU_nJKm56}@{m!AV^akJO1TEWI zf{x2PNrvWHm9pTXtrbc_6w$o>M9mQ%HlGMA2vOtltqhwb04xDf%uR^@BSFESOwqzb zWln9exGCR{JE?#jDsZi>hJ1e7vw!lDVosTEQnXO8A~ejYx^#j-GR&%#^@Ms1>W#?< zoa(7?aK9M-tY-&Z#9TaODX=uNaH4Xj=>$iWF+p2!0F-nj8m;Yt=%7B1!R|&{FL`=H zX3P}o$5cl(nehi9!c?_GZM=qdKKgJxL5|>D-B^yuGjk4ryf_Z%b&Q=uG9L~}p`7Pn z@y0*1tQ_<0t81eia?HF;ZdkA z;@w;>VSO8<64K3OM2V(`34hjMg~=0F5WbO+I})d|H=o$_@b^O5ler&lq>xjd;WuJ? z-7+{c-(}y-b3~slbL4=k5pa>V0ZS;<#Yg?9#_pVJ^5c~OZx2qp$(R1H`st*#->t#*>hX)59BO-bXZ&XIYj%gx#i|7m;cJ^k@z^3 z`SFzh^I;%8_lNTfeWhjMt&<dUMvM4b{`wesWW9x82?M zv6Wo9^Hz_~X}7KA=Xr3stQa)BsZdXzF8-1zPdK-|8x6+ZG z>-0QJANjGC@XVlv11*H_efv=@P)_5}8o(4dm5xIltbKKaf2`+zU)r^YJ)!l44wRXN z&_+yu`f-z!P2r1zfSrsg)A$i12bVy71;!nbOv)yBDA!^Yl|q)pwf?Xj&^e6l%x1S! z41qPX#J5UkHB!hSdez@=GDey=OBuZ2P%C4$8tuEO|ZDs;x=Jtsg^KJ^BTfFT)7smK<7un1@ z?P4v5ej4$t)bwOCe%_xw?RN351mL6LbU?#nf+Evf{{Nh#jIhD*tq}h%`v0wA|GznE zpzmn>pL5h%-O_4v1(nR1GQ7kYSt}`55@$o@iX_5%!T@L8Cc|>F;erL8_JxgRtmI5^ zy$Mf6f(jmHI0~izPn9S)fwsR1|3bGPAg^S&p-Zou_!plcux7oN%FNi_oR$Je?!lUj}~7j!Q4cJv*XBSjosU@L8L7$6Zaue|ZI-9W z^)+Y8%|B(v7;v^c;GJe$7*P3T)RP)^m+XS>UIN5VYvA-NA7luX% z8BI|MLTQAGC`%xvGIyV6&mvT!sG;uG9VtvwfheeX3K8)FAt;xknodAS`^J*6kK%v} z>Wm80Vx0VxmsgP(wt$SNk_DEpH(W7+46(k~NJ8A{UrpwVn4;}P+|(=@C!T~fUIrye zZ~#?=L0GAnzyzU1w4tRy`XI`=?F?vsUNeZrL&h3hB^XCTNr`X(BFMr{G|uvw=Mj$q z*^pF#Sz9fHcgcjv!azzP$a6#v-ttDPr=isFCH)b-{cv6iZEfNV4dv? zvJ;}JnJnNJMMo_;iY37x zSqL#BRgh4PupAgHCk*Ml?tyb!qqge8JX$SNwFPqYM*M^b=TIjGee}0-6*Xko6bHu$ z3@Y%5c|w?*l!l16K1_lNtXM+a;LT1dP8E_$#)6lP7Q~JIT;ZEMCkbH)@Y#T2$CbGH@kdb};fD84(w|$uUapR7U;~ zgkG+70lXI&Qy-fw65#J(az1c)3-~l~y`jU|ZwAJLj=SbEQ$h|R#lxfp5%DlHMfP0N z%1R(+w8*?mie)tK#-%u+CJF9Mv1Qx#!4v?P_$b&pGbDrzFiRsz)XZ3{n|%xvz@)ne zv|vd@of}Zl2pT;ed_3(&s#8gySKwtT0UZp9@EBj7H{4**&Nd3~;nnM2SZ+|Xcz&-u z$vqL&In@?Jn>Is6fuQQuynRGKQb8azaydHv9Z^0pgOK(SNKxyYu5~37ZX83EepFr^ zj3^D(o1}-Tk_Z>rD0N7`2V?;$p%zzos-i@&*%MjeN)Qq%n=bJ+q9|?&H!dBvTR7L0 zUm~a73kt4pgcy<(K%Dqi#c9>NFCTR?nD;L*1rQ0q`}%J&fI{58jsOw@&;=M2;CmXc z$roMTcGN8(6mt)J8GaZz7SP6G|E)1w((WqZ?(7@IoPUf4BUve@jLR6ZOwZtF+O$ll zY}cSk%ENhO^#)|6d&c=G<}4$3hn|tf+uG*t{%Y%1l`=nA;xuDcjsYJ+?@Q`wdd>&u z%mGN-?a&U7vAff4t^be9GkB?QJ2?GH&*!7wQO^5mPVDXW zm)-kH_h}IScSY^{k9Yg${^RTIMmfA8`p7Q#?bFi%&dok zzSnBNDd!#En^iJV&px&NS%bDM?FEzTrK-8;OssPFEUO!d-a9=7c| z^b(&LJI`cIrwRg%ecSVOnqy|O)=s+^ERf4$VC_B>c^YV?9BG&8et=rHhIPsm(&}S|9i0B_$i{W2cUR>ztLtMGq#v#7Odz#F49*__yRG3!CGqhjpmc zZX0)tE{;r^Srq)r*&5??E;~9Knv3vhwU$)b(O@U)tlcyoHgkpaJxx|eVgXY3c1OZ3sCOO(={z0_%vucGxMG^iSJ z?63a;JG67{@YMfyMQMNm0FeIgPotrgvA)g!HkYX?P1$^+)D*8 z=co!##GTq+P{KZdw5J6v3DDe2ETIs+;%#4{xtR1~pA=a-?`Ib}xjM!qRt+en1{b75 z!p1?=0D!pak=POBQ7c&Uo>OFtBXC_Pm+sbR_02y)aCmgC_$$;et)S;|$VqGW#W+yf zD7asmSxY+67?-yA2pm5GabdNcSdmVjp38}e=Mh;ZDIzm~Q~+6M{wfHxyQX}_XXPH1 z-a_Y|9&c)uvraHmbT9LoaK?WeDyh>S>Ov=7>i%YZR64-Hvk=duS3R@FPl>_$xg^FP z2obzJyFNV@=6Lx&e!ggb-5~GSkUJ8IRr1h1bu6i$#~4a6NvZ(P2}CKLn7C(nTm_U)=^823GoS-jauzaR$w}!lw zTjoB61~zt=y?8iW&!9IN!(1Sq;BN9`hm`*OJ~=pRmPAu~GPKCGh_rMyi4syR-6+B0sOo=nrO~J~>V_xx~8O%&Kr&^b3TIHlO?t0Zd z^VYX%Ge*yI9XkB{0{kaO|6rl3d;Qx#hJpY8B{f4^8xwQW|F$iv>--;pP8beiGUl$? z4q{zy3Ma~J__OKYBcmCQS{idbB3E~_MuR8`Lckj;a4>X z_LMJN9}0(|&~zppqCXt*7elK`G|*ap@MF$^zc0c&wZmmu9|+EEwte^g=AD?5u10st zeoIh4|4)~~Q#Ni4boYS$)_aiUvP`R%>qcg^iQe=RO-qau{e8)?dS;6b zx6kBDfm7v=3h|Lu=yb;6$AQV@KP4`P^pCyPb=`4C40ioS%<{`%i!%Fl*ztx*C+36^ zgqLAwO`~Ni&u*k*NoC1){XaibOCJgc=xADtx1Ua@K&)E|zPU!rv9>);{aQb#)A)cW z0_!coam9yR^YTk|$#DYiBbIb~Uwj8%qcJ<5hp2#1=Y?r|etLAF4u4C0& zEt~24Dvi}mmkcDf>6mDS>dF*c#I#nXwZR_g~$<+<}8m;9THBp%TyaPpa#?GAO(@uGHOy#nZa5Dvg6oJ~xX0^_F z3-<225<~VYx4GzwMrhlPNTBCyj_4Tc{I<*)!3^ivoUxUz@INk%i!&GNe2w#Kh0-Sb zyo~A1m*=*peshi8Xt*hVQVyl$1`pcK4$~CVFMo1E|Aa){Ih6UzoGcFjq+=6|0PQD% z7FeVM8Z!}IiUli2Ng9|5sT{);U;sf@){b}KUG$FKj{v4eIy4A^_$N|5WOSKPB#%cZ zK&po2$N6aPuL2~!lbiNP!<7M)fM{~*p2fApDRzpFYn2pkF*Ggxl1e#;s|4>R!?w!^ z6=eybpr(gaR6NY0(Z#n*^D62okp;%FA}Q(}+V0yW_h!#67yYH63@oyTIF<}X8B&s? zB#FSWr;5J7OYeMDRr%okr}fy5xt*r6?;P%qZ7urP7D*~el=$l;tG0hp5|;i>^}<%> z7bhkebX%%XFyN}fTJ`p#Hw&O#SgEKWiSFeRq|_E?R1|fVUqJn8mhtB-xhv91NHT%v zzaPizQ4*6rCJJDZ8jI>34i_oTk4Jow(7z0lgW{7GNHfuw!nrlE8j8juz(9y%) ze)0h13Ul}r5kwD|Hod+n;?&j>{@UPi;8llJ%q}RExuXbCoQ9hep%RB`*!UYe<-Q8u z#So+nVoH+U&tsm4CB&(+%;jZwb+hL!=qK$-s42a=BvO1}hxnCPihV(t?ScugqC|W2 z)fMzkN5Thxp!e~Ld87DWi!8rFCxqZE@B&j8pAUgO(kev{v1VbHoj(Sl8(LQPDy)h5;#R9m(w24RKAQYx)nn$6>_Iu#m+UV#m-2EDw05Ps?Qtp zGSgC=Bpw&yYk{s-p{ZWYuO8K!yBO|pMb1EX%-^Qj@p^}AN;PygbB%D_@j~CoWQ5=7 z9CqbzgTD@3YqQT?afh&`%Mvy|Md-r>v11~f+%BO6HOC81zjc3+cyxRF_kBo|+DMqX z-K&UkMUyL(akG~i3)5R}mqsYA7tabYP;vEDh@?`2e;d)f8)%MpaCcC zuNsqxnA=26EQo}EIDqn#zSGT4&Vl%F71C1XE2gKRZJS+V)*{#*T0MgXWYhIBkkTTo z`vcPNj!-o#m5R|nvI@E43CY$0a@pl(F4ZA{GEn__1Lhr1cYSp*v8jO-N)f3?pu#XxmL7?OXH5^?=d1_{?&cpT^n32g*5p2UavTQ~VN)w`(WQ z6Up07!-RL?8FMhXYBt^eN+>Cju8(henMcdpe&T77Cmh4f(~W27mf@RGZLag;A;BrO zma+1LaG2jBXj0k&Xi~b0qD@W1*O8*>^Ry))U*mbI;AvLBSmGYd)IIP*$3TOw=_9RY z^N!*O{;=Mx?yCFs?C<(C21TP&p)Vx_Vcsgbm=+k`+Ku+mzmr98W}w& zbp2?W^Fi(Yg7Ny%TS%Vb<8~O_>HD=Zb?N{l2u?%mVU`Fv3={EJx=YjkUR>#NAS z>~$RJ+x4`?9$W0|^ID95rdL8{0zF!j>PxEgJNZ1Ff5JRH=U-Uc%j)eR_uKYy==xP( z4Zqmi-u$6_EKcw9wI*Nl?eYx2`);~>i#CIMoRZBI{miwRUHM2;>%4;Bq5GZ7Guxn2 zUOja6#5H^8zV=j2txAK()59(Xc~aSzze=Ejp!h z8WQa%MHzZ`s!Im{04=W!t zpQv@f?nZqJ5$n)zJY_}$WqP3r9mKXHm(BLZ2^m>S7OrJMy=6xx?QU-0=w%8sqF0Wr zn~itD>!b?~KAU<3>uhQC2mODd+90RK#1uLJz!o_Gz&~31-_ntxt;2uEPkL#1I$t$r)^B6Yke0M3{VA|6D#}~y7nYJh!jf50Q z^tg1Fw5{6)tgm+R#XHb=j=?YHJKe(7T0I~!biks%>(w3B?0RKtkIx6wHs#w;EvA{z zgWkB#dD>0PI2=8sf6w#l7Dk)* zQ_PtikgW4vg2>$UvUB?T?F!F7NIZ(!bZ)7WCf)ZKPFFU(qdh9G@iSztrct-a(i3f` z(Z}B$ikINzRx6J${7N;Nbtw*emGYtJmrAIaJ_fnn=K`+k8RVADp6>sS1#N3Fyp|xymN>ju8CpUmz*jmB!j?wysgaC^@XFnkTO10 zyl<*)%zI?(I^v5tW!O{EmfzE*XyNCJF|1gqn_cP@s@OO6kxmhZshX9P*E96s9IfZlY?GiBj49hVHOh=M z1^Xzc)R!*a7igH~m&2nL0pml)OIgfOF|tstJF3~3$|Kb$OL?Z{^Wkj2Pdti8;MFUR zmGU)p*8|X{uH~K}T30e`J>)`FcWj(Iden%rAOC_*ZZTy!j9IsA^_+NBJE|J@AUWzkZ8r}*+o@2s1T{_U?PI0PmLta0xnc^FOJq5@qA$RA1!IfzgAmz55>i?G z=5L+1@e+@sEm;3dOo^kwF?bomf5718)}oXVy_EFo&(;(LOYdnp$)>lAD(zVzaNxRZ zr!Hb8`Qc>ASJz2Hd9)h%Jcu8*miV;J;3ZXN*c%BwN3vUk{}Xr7Qe>@AufhG*U(zJw z$70L6Mo`xg^kWXvz(zy#)QpaoEVHFj3!&oY@-=Mb_}^R7hzNqRc}UPBxwi#Ix6HJE{JISkN2dQcu~y8qG%6G zj3CP}mYpdLBI00w=p!-J{_-puiW$yFO<~a(;V$pQnxN5$hpaZl+4nAmd(M5>iXVzS z$ewKDAbraOW|xcM^B0L^x3(XT(qrVyDZbpqIb^sj3S+EH}WY>L$>{gxgGU8{pP!h|_>Y z95_Y8mjTx+AC`s&)-r<`femA+k<8rVDVr2GMAa&0?O>vqHXu7JM9D4iN?WB`A+1LG zNr$ithdT=V_&}*}GgL96F^s0^A7;1D( zfJ<^OjL-`kxu1kFaotx(^eV4N5_=3ZI^rOPom2c5j$9>+=DY;R1p8@YrFxYOWQvj5 z1BMXzO(wm`n454Aod7$Q5HVKqAq7wX1~9ouG(qU{@fV)FBlMDum`~=G;jSS!GsKwS zZqyKD;5&QZNHRzdp+W>>`V841)hJz#%1W5(&Ad6;t25cl^QT~~;QkR-GJSl698&`? zw11N~$0}8TcMWKfA(kxvp|n%ACEp=qsK8BzDT09;vRr-cLxUZm$P0^vW9nU7#dcvn zt<@cM&2lRqAy-jgJ>3lH)v&2BP4aUsU|E6Yuq6wmg_vxAA$r&mmxd>TgyUUfD83=7 z4l2H3s?N*=5;;2`DxXTmwZN1*c$7_Q7{q|Y*qo<5K}*nTM8P?wR_SGJ2?D1F>lEGZ zhUm*C7GsI2Oo)?6l%SNNn~o*|FF=Z^txl8mzmm z+_?5}1j-sU>}H8z&2!|S7|NLFk+*kB+Mqd%622;l|B(yP<0BaC95&vsS}VMtRB)jHzzMLPqb{jRlx1mI#drhFwASaK#6$uj(}A7 z1GrTaBcp&E5_ZECLe!EohG-B{v^G4F9>i4#ej&*$@t$|zy~hN|*)Cx?U|aH16x2I~ zq(cvQTqM)?&#;5&C}~gos1+w=Ef3;UQel1%8`BoA&=yZ*+d%PR?zLd)udu=08$M%O zaJSY=P|Be+7a?$|92t|OqbW{PpL&8>~dARA%RG(sIA&;G{%vZNT?6rjMdnw zqJ?7xRH}7_uo?P34gsP#-O8}DgHkhk(h-L+mr333%A0fQ8Kph&z+Ycij6b#^p&>(n z+&ty?m&ykG0cO3{gaJr_2EIf*BF3B+6Rf_UnHBNWWL7B9-c`(pW&&a>=sJn3V%v@Y9?`};YP9ftJ=3k7~TEw zq_#NV3V5mN^7^g8o*8==gx1jPdhlN(r~xUw@OtK9IC*kV>^$E9E?e_7 z!V%!}rj@?aiF^a&sIU+AO~QCR6_VB=2O$-1f+96_wyBh19s7GgUKS}Cf%CR)@^qO0 zM1kOVoMIfv-mUXcm}u4mkHS!By!pNUWRjYoGC0Nuvd4x6%5bDGPatur;xV)3j6Glo z+QE&qo3)SKi!LO6RbQ}mFsM4B1=n9xU)&MSf^xw zmx1@ff{PN0IN=j#q!RTc-?!tALx5zMtrVFM;Uoaak%U5fvhSVd)P{OsiQr3OAZb3T zA~}Xw#z}_E6&y}A?Pf-Y0cNn@3K541jlGp{_io*$J9;~+e86VryvgLVR!843Yz@4C zm|HhQ&iWG`cIXtrBIN>O0{E^kjzcOCicy~afCEnC!nQTVM2(a6kcg zN2$ROJ6uY9)~BLp$Q%<}nse=c?*sk=a|Q=kW@yIBrvM?tEccv%04Bw2o);b9iLTO} zIOhMVLwwL^N1b5~x7;jhV@=t5z?=PY5G%#m?hFV(=LEh7glFNRZq45;xdR%^mxjiBYt_y>x|P%r5j8nfC=`vjs-JL+d%EE4@{D z?`Z~3{u&bot}#>}N5_a7oMgI*b5G!YC0OzMiaPv_)hq8Ez{3k<{3U^!6Ax$wcf2E1nej=L8Cpu8;P zY?{siHI{EujFYny7j8Lt%t-G6`Vg`YuU8b#ovXr`3&jh^g^Y@EjijDvMOA^}w*Ex7 zlnasAIV(la#7n?6Rsi$_3G0t46Q3mNqbN=lYrQ8RnQ7Y3qLuJ$%IV&nRl6bsu2el8s*3 z=l8gh;idhr<|j^XF^tsvVWrdAC2m-^HH7!m$Oqb3za@m{)X_T#NgtQ0qaeMuiV=i9 zPT2F`xK=!}4ZX1DNh!Pe0FReGIPY;%;kQCtjoT(XmLanj46)QFrc@_wKRQ_rq8};q z%Y?&&A;qzn5pJIS1-)zl=eU&jFdF=e(;t}2N;&>Od+8y%LANVbk<|$iFC%8cC5Cu_zU(KKSIWhez*-_l1d$FAjr<^a>+A z0+^qH1#kHyzI92tvx7DG9@J+wU$F?6UMOD_ls)q4??C5ohGA{sSl>n>UrGJ82!j2O z(ZwjmeiuF8i$!mY+dr6eJCTv}F=44(=*yipaV;oH8LD1GFzbOB4j>wiv@+=jRO^+k(V zO~4WiOJ460hM~_1Rhd;geUsxnljA;B6~D9&dx>@xL4GqDsK4T(orGB}Fnlzlm6bfk zUFxYCCzvunN+)&`6C$0wlJmaN&7K*qK38>{xT1f-Ch7YbdvOtK52eZDZ;)&6r3=Eh z;@)&-)FPw9xANR*O)bA%5iNmW`+n~PW7){OFzf9T-7&wgAUy1g?pG5J*nNtpg`hrLi8K@Y`^kOnwJj}cWd_C-(3qM1P-gxUhfUEF=A8cd7_;astSbkd}djGxr zXv4WIKjO2bwn9(2DOoQj?3?`L!`MSFv_L1jeV_lTcy7s!Yp4W#1wFdAvvqAV$vcqP zrE~>?tcw~t!n?!-zCex2WXMnNN@iTUrS#hnWPMSDcFACWfU$VsE`J=~V{3J(u@~RC zIXr<(Z)3uG2jt0ecy9^Ic94|?$2lYG)^apaxTB$!C)qHZ3pT)%?^IPXrdaw-`g=x zozK~hZWC=zKR@9{R_OR7eRG{U=W=h)77}l6p3Gg}KQs7KbsEGv--^E9i$N;o- zB1;yEHwAxFohm;*i-ZfM*^ftm|COEq{Ql}BLCYwsOn<*yYL9CpAF9 zZTl4{MRp11DSfuBDYYeUqKO#4iQuY$Dwfriql7G41-ubNHuymbyAS1aR62pM$|PuF zD9t|A2l1Rx-|b$sz8CHtb|=e?rwWeX+9NT!ZBJ09+t%T? zSX<&)h(e$pAQ;gHjL72}fK8o(?2Q8UxwAbPPHPmF9_+E#3wy!(;71W_tm3!ll>oim zBYaqg<&W-^@xt9+Gm!VQkct6qKQ6?--*wOoHA7+$VhL zPNy|*{wQ`9S6YJB-b(K&0hA-KbAe%?)Y%{ z*~Q)+;wi_Z?O4u2_3i!V9kK3eaXI@bFl7y%09ddnGvjF9G~f3Ny-hpyb1UNIPqIy9 zX);w#Uo#&SFHB92twsG|)jIf_%!~ZRO|B^1`btutyIrQi z<<)F<1D4TwoTJFY-1TEoKNm+szoM=hx`Km@SFxhUQ(*k-Luw`BZoQf-=n)G|nIpPf zbS)qr9C=8-9>_P3FJ7JV@<;z>J!^?M^>*d=@-B9h))jsRXVY7$V}_|_y{(nq`DK!N z=LEc7P+zY2(Ut|Zr>Q8JeLXs}gDx2|q#~N?a9Zq8cBWnXVjw=QKSP?`u}tj1Pr4v3 zXZh%5pfYgRzP+~5SJ1SpY7fRS+_~?Oa9gKE|4L40s(~JJ5Vm|Eoz*&I-o3UWhpg?1 zj+OLUzB|>FBLl-eZpvEi`tpLp8UAJLTMp%ig{dQl>RZ=k^!b$W{#hRUkNU%aE@@|Y z#;DI6>hEFS1a}o*;%5&h*Zb5=jo*s4?q=+&rrav|5h|oh&GGfe0L6@hyuG*aXx&7# z<4vu+1~%!;)7`$w(n!jeiARsto4emfye3Bj(~Aq={T9M%7=4Ub%xpSR1R7ZkLt>QIA- zB^R-@3YJYxq|X1~{55~#3XV`imQgAxs52~7LbgIBot>kW0KL!2QHnFCicq1jR?HO= zlz|S1M~5V_-$&H9FbK(|U!7(5n@qKH_W}Izw-tVY%&$+lgS8}D9(tms+6JoOVIYX6 z|Lx^wqJ!$tWc>4spr`vWWYZ|A71>frcJ-B7t8o*{TOyY%Nu_!AYxpX4T|A>Ce$GSb zYH+C)os*JiF%Vj~WR!q2tVWq#vT)A9RIXOOKUX9p<=E8Zr6hTTmGMVz0rM;fWU}e) z3*q;Fv`#&RZYTr)^Ev-l8TNm*PW^YViQ#{DUwdmnJE1IN=B#(FXVYM&Oy3MJP6jS1V1HSFbJpxSoiiUzyLmyZ(O8zWV+i{=CY~xY%qc2`he?TIa7s zSC_C!DV8M`l=+CM8#drYXU4RhM`S9JmY*UfrpS?mI)th)XDl2zM65EOmz86gu%w5@ zoLA(R$hs1xD=CksQJepr%?iq5QYkGrRXMfMlt0~&p|pnZ=V(GSNf`u&>r~+_!K{#8 zR(9|hQ`8J!daB`UksgsLfeB^I!j>;*3lx{d#?)yZDC?*>=RB#axppaS-c}r3%H}|x zwc$0dP^>x`30;1JaB=EiH1dGxN4J1uDLg4L5m#~~W${*F!!*SB0t79eh&UdPnjp4d z;j3t~Kfm9G3amDFS8={sN-%H5VXhMWqpTvf%2H_xGZHg?VrN5ET^4SnrMhL#Fg{^c zv)rve&7dPm3pG6GJLY6Lc@HFGPOLq zPi`g;aqNOUEXq5_x9zrev4?lipc zsuvQWPH~v!bWD$GPAG>!qDvV{*{3`uHExzxDPfWR{SAkaWUhdipKL)XheFDybm)^r z<>Z8eF>ppaoyfewSE|^P(;q6C^Ghl1ki74m?+6Xl9PC(`hZlk;ts3Syj6LjW%|qnY z{>YbRVRZ%+hRPADYR(ObHCsdoyCBOtOgJte(U6m!G=g3*DK(;~9A6%<=(bNrAFv%% zQpoEO@xu=V&3!x+b_`zu>W zXKgU_JD&^u_PIS+7vRLs%3lCKkVL*p_=!@yr!=k*lP>m<1O)d&)W)VR{<(lGrS;*M zP|ufi@-fFi4uP=}1@DNQL+SxVTNWagFa*2MYy_Hu<*?*MVxPB5Cjg}<1;wyfqCMD> zdfkg9aC78H*efJd1Owkl5l9nd3YBy65{~5Fc#Y8uAk71N-C(SggFDy2M+^%8gmeqA z>?($n6C45d9lvoC^l~svEZHjG5sD401?Hn$04jHnlwxmd3YvPI$O-Lc>30ZqpYo2A zKrlo&%1)*z-QdrV*H|yigPuT#8DUr42xHfv6{QuUHdNveU6uj*{FKlF%#8@KHc)V~ z5xUyI?3(uo&N~Mbh;ER0bYM>Mo?UU9X(XXZy8!dR7B9nQM34--Gt?iqwA(Q4zXb7c z8Uq5N2)Z4dBh>i>X;3DzMlZ-c}~xER8A- z0&e^+C23w;-Vy#KgMR&a@D4!eP((+tLipf)wHPn4_xpW_ASI~DR+tYefzp6(QYYx; z9HgMYRBeNQAUGAqAeDCj4}d9wA&GV_pFX;bb^i={U8zE_qDqd@i@MpRd_}MWQK|@k zCxo}J?A4{LL_{*^m&s^29WYDQ^RA_+7KV3`DF(*zD-w@k6IKLtMJxwBnw3n|bOMOC zM#O!c{MHWgRKk@FSmr2)ny>ChyPY4%Cuni)h5Dsm#m@Z!6K z^#j#onK|`QsISG1_hx$NT7CVze36lS&!w`rZ3t82d{>USJg+NEzJyQ zN8PXPkE=|=X!(`p%paQd=AbX-KE7y%%R?U1h%xFPBnm*}1z?@@cUO>YPTy1`uoPaC z+!WG{ad=NH68|7&X+H&oaQ%^R-Q$08bxuK|gxivC+qP}n+-+OCZQHhO+qS*iwr$(f zXXZZKIT7_z^+#0vk1H~BeR(e?&_gJh5ujf)*pG8HYhRL@4j-oCXBBd@luMld2uc8b zb)UMQtwqux(>6lp)rMWNDwbhhcMU;4j!s}wD3U~m^XZjm6`Zs@d1QC-#gmRfK#RE6 zoMuLAqxwLyA;di8@@8E0iRP7dDY~hf7>E4+m%fNoa~~{$U5=2)v0OC=qRY_ z3%UVL8V#rcuFf?9dJ=iy)VMA&dseTcDFJq{yqS{<0=&y8?TF*tpl(pNFX#E-J2V{? zLW3ONr4Jmq0q$RCUZPH;t$xY82lz}6de?NL;>}38>p@6Ot^xb(q{qknuxC#~E<(@e z_8P;+p^f&qSXc{Q6|XyrK&5^P+io@z)tXEj2oq)IrA!qO^Cq+`_MT^BQmhAu3FMSj zKU!G>Ja9h+gB_z-UmGOVneE?JqOuaye%ul6{ChetM27p)Y?Yb!8wnFSY)%N%H&?vqurVe;kZqG$tx|m*x%lQMkau4YYk{ zC_C}z5Ofeg2*VBn%oqGiO_{Qqt?_f>E_g49L%(a%5FWz_9d;uWCkmnm z)sS|IL2q;>71o0?B=;ChvZFC=9MlM8#M%GX8?;|Jpo#>eN)54_1sWd!F}$0MT9x*X zj%rm&71m0e&z?FhNZ?bm$Y_ruS`Td`x%7Luqq;alTkDoa^NZ0_9XWOGAG8t-L!kpV z{OZ*-N8-B+Vy^EEX)l_y$s*#SAB+{LOLPPp(Ho53Zf1irbr39|rG^ z&+(S|A?DVtO}8`dBhOMF<$Bjjm&bO0)7(4XE6;=2%Z~5EXzz9KhaCR()U2Kt{2p)U z9Ti(2y_^TlvDMn2`}s;?xvcN$j1FSYa=kfj7r2z}UYiTjj|Kef?>-FO@5lPk+-V$d z!yV_=kLRwAlf;~BpQBj#ZnvG$E%F{-cITOpGdWq3>mMI8;qx3%`YvCYo8eg5(nC?X zN8TN~uEx$cCL52ho|BU8O8%#1csbb-p8z&jn$EMW4J{X)h99bx(giv89T(Rra@ViZ zi^!GkrxQ!67QK&oUf>m#<#r4DYwN=y0e)0(X?~kj_nxETHdbX{z-lL6F?ropz z$q0cf;0qJHcbTPaxtorUL0s;MgR#}|pQhgZq#uv>gL3be8*LZ2r5sB>FNY5$SlFZ5 zMLZ6N&vW$Wp8CUVJzfsi)0cGX__uHWme3eyyfzQJpUKLcz$@%tPd~^W598t77~KZ} zQBmjq%$FPrtn%JB(^UG*-Y0nSSbQ9JuaBer)mH=S*+fsH2T#+-VRqb~t23o9bg-dn z)KuQ)n!MuuT~C?Vn$CyBi}@q}&$A2sG_Sp#P%Y}#O#>^&m`g6M?1vd8wXem?O}F5S zzNee+-m5^hqS|eSL~VzS%-C*K&x=3`cTTSMyF0XzO@&#cG6m154%~%OG#)KAUc2*I z#}9NC{760N54Or^;it+-CN-X&Y|i&Xc4*VZZt-uf=g3ifjW?w)4fof0 zW^&&U*xT(ziq&ed3;sg6`bUh+ICm1ikKV_^w23Nre&{H>GbY1*ge9cr^^W zv5Zjr4?0QHoR23U#Q-RYUA$J35pY*j{y2I0P7|B5q7R8WnO2&gr`=Sbh`|l+33o;{ zHU9}znoyq_6dvWbaYgqD%VEJ|Uk>#vrtdNNd4{1+87 z{yvPcJI_>-uqaMZiX~N2A1oUqe{IB-Gfq(<_XP-r2!j5ML9Wk7%J= zt*%7PwpbOhytu>$f^8}|x%}K?rY3h%f@m=ayNr-8}XPhT0_g)&sJ|! zntVm4!cMS-NJXyR-N6-REz8VV0oQ2|_hZRK?8rn-pI}+F2>V;WxrA83#84Go0cb3} zj4ZJLGh}3_4z1ps4GP1Hm-h9Wre0Fw)-ntU2jB1g|6@`@-uevfzbm02)c-psWn}z6 zh^Q`g%iow(_R8z{bM$`ZZ%isHPT)5t1ui@V2S!!o_fvGFoc-kXWw4k4RH+vgU;qtF)$F!h0aAT7vG5 z)A(i{Qt3^_s^x&5{A>y>DgI&AqD<#3dlYFy#k-KQ)7utDpIoWQy}55i#Xd#gqClEz zPq;YM)H$p?b|rms0=1^`$6+FQpe-}=B{dSYl~(UQ6&`gHuI_I&EfQpr>E`3NZgC}# z(j@-ws$y)FJSBY%3R8JQWzH7^VI#-EbjMP#s8MEz*5#W#rKzdZRr#1#y;ahAP3(#R zvRRe00*S?i7ZO-yCZ&3o)KvSo*2CJS0c!On$<^z^ThxYzxB4;W(cQv`8=*>$zS|`U zU>;OkyJB&f5uKzllLdcpAIih9D2n^=x`xxq7Lkys$2>SwSIYutDs6H@``PoN7ZrDB zQwvYd6eY3JSyQS{Tj1Zx_I8K9NGMuYqhz^nE1Ta!K7GQ%ih9cFX!Oz))U6FFjWo4! zwFq20Fw|2g>n0^@hgZWfV+K^IIr>M7 zO_J>n0Nb;+T3o~x=1)d0s=}5{AY+l!32!V&{F%dSob+XIqZ4oT%I{ShO3^kZUCHAU zg`TrAYU3!|!(pLB{-C&t<$F(iPrvF~xobrN@YMKrNzH&oU?(sFb24vRLu)yFC5Sh{ z=>_jf%xFhf>+(NZ7*kr$#r$nBxWy~Yxeb9f<}xido^t`%_XxU|TWYPxH>6X!T-zmu zzopj?-!Z%Iw%RQvtO5m$36qO5-eGT_!qV`hUwMvRAziu7>#MhkR1SenC0JLqTWIyH(0fC$f4 ztF+jg0*rjBoX?3nuCUoK89&Sq7}`=Y*X!YwoGeH0W(zIJQw3t>v~ke6u=|V$K!NGh z5%aPAQRktY-^qyNn8hVcgRI?kJr%i-r9D%eI6x^VMPwU;D~L*WgIYdgT_S`IOa*;Q z-B%;=Y${^>f^g<^SD-x-nlT4UjyOWI<>v!jOY-e;ukQ$=I%gN%UXXN38afKmKnoRvgM=u)&RCMnM|M=+RT27h4VCPndfvH7q0@{QQy5~7nF2YudA36YU z>{iMhd5NshW+4etjO@0`fI-Tf@svTRS$sg(%W&iT|Jp`{LsW(=mhikNP_g-QhgqC# z5rhxaR^DPaiYCD_AzsD1hEoGy45?uCA_Z-!hSI*X`k;;vbarNNSVjL{B8~$roERv@K@DyI5#}$2yvp_*3{m z9j>!jHcP#zrPT@qC!=B^c0>lL`7jCegov3N2*oP6!LU+6%fhg{_Mak|$UgOX_#a%n3K!6P=A97rkvjlbNV7k6 zh;o4z>C}#qHTc@cHj|q0x;lU!G(AFtnGbG{e~9c$d8;*zs=erL&MH-b~=qc z7w7L-<6-dAS9t{+YuZjLOZau&(AQQYM3?KqF6+i=X5^9UV`!aKf>M{~@z4hB9*1Dj zH)4HDMObzP496j)9Z``A7|iPoCShygVHl)=NXqhy{>{%D!1KJUGcR!`o`2pUigwEG z-f?hlj|qC~TNu=JR)u?_*fROS9$KT!K51Jp3SE95H|q60ljvSl%OYUQu*(gEy-b$x zmNpD2nB9RleIp8gBI(n!w$;d-HOpxEL6IR{P<$xvWhTz^RC64XS0&{lr`c@Y4;~RwZ>Q`@1 z?IMI{Wm;jDX2pMSyMoE&d;Jbt((;dFC>YmT2nSd@D*&Cw0w2~YO@U50;;(MrNpkYC ziZZZFki#2-31A(CSp3+Cm;{F2LdIne+Os5crAk7Q+^6IK3PJ? zU;`cFAx=Yo`3>r%q`_;@nXz)0$-Tzv8p08RE;Y?T44LY*a537imrh`1)n%#>$yuzl zKq_PM(QKS(h|~oFNWF5)Q6HhmOVAoH(i4UmST&eb)$IKdVREa9lvNNdRq9JshO5J% z;XMB7NFUiG+k*)AP+1L>s*Bd!PLXY2(ATl*xW8LN!z8SY-reV@9An!3g37+ zMo%h52cg2%*Z;);@alxYbeMz+AuyvQ^;yfl;_98nX8}ligN#Nuj)M48!H*F#aE0fF z>vstZyT*{zCyJ>VkZ&BF>LfAucZ`wMlCD4l*x%T>3d69!{=MFy%BL!Aw0>YiDKyO8 zA{pT#M?jZKMut^R$I%bTxo-Oq!5f0J1Cq0Ymktgy6V^VA><+iZt#stZZ16Bi?PkWF&Wgmrm^;Gos=bDB9d>p+!%G3_-TE)J^e zU`G-MP8!P1^6MU5=kA*Sxmnsi>&yDOK&YtT`AIWupano3+^(c84d9A?16{8g#*;;o(%W1Awl?%MN85)rNipJm-HdHT1FM4hQ@`Lb%!k_>iqlxOgB^w4 zoqZP@(7~t}#1MRlSGkt9P=;qb)+_!t0=}X<_+2nod+${K_Be5VcSg$ zpgewsFXJ9IOa>zp%3#wS9F#@Vrf`^ZQdUPRVpH*b6#pfXG zVn?j}Az!fO3ve@E!QIEqb)X^EPuQ(QxdFaPohO~&yBW2BiYT&xHw?fNCBR}SpnUG! z>+fF@0m{HL0M7w|%D_+{&C~asf!6tV}gD3qDa@~Z# z|7mPi>lfbF~Z6G07Pr- z_M!g@PF8^0ddlKvPfwG3ErNT|k)gBx@T{)8!eIJAT>czgGf?x0J}TNg5FOx|XLu|? zE1oyD{G)d8gIC~30V|^L3c$QDPapN~q*^@ETOSNr+thgejj?@a^n-7;1Q2>luf(&B z;XRyQnCuE2Z%{S{P7f-Z+7j%s3G@ihtXe#h19-u8-uomVKDa_XfciT@ySC<^MyatO z-zq`&=m*CZ7SBGwwQG6;THae5(JLGn$-F zbH(o|&mcTw2QOo7Za}DaL+R>2Ao{$ww3478mpbzFz7?J!=4MqPA*BR`er7a7!*Y%uk1J2w>F8jE3Y$k>I3^TAH$7RQY)>D zPbu!^U({Gnlt%+IU3lJXWIkf%->wX*eXo&lI={J9y?uMUcJ~^+&kWl7DeK9Ik>N~$vulONW-uee$TYWzh#Mlib-zJH>_QWs6Z-!o+J zM>D@Zb)-K-M0yuLtM^{wJRo}MUn2P#O%b087i|$paz}f=UNm3}N(5aqeF8 zX;UTt#eh&$62mLRZ(#z6nC?3R*+Npr22p|Tf1M9xgm}mLTtx48F@RwrmkLIBB;^Rv z-?K0V!Kll7lxE171>^!$@Gk*KCny2zZ{wU*9zqjXP#8f9gA@_83SPxBgL}RMcBi8p zB$~>WySI+N0XY0~u8(N2x}%un3g{sEITniPO7MG5yrdU`@!Si<*oBV&1j)Q@7F`zu zKMvvdi2&`dn!ph^Bp9X!SS{vEcHyW6XuQD>PfT4uoMq}W=&lh=FT!t@Kx zB-|1?V>u{o+RC}Stjyl3(RL&8$J0)1q@X@n%1t2F>$+^=UOXG2kq`rt5eHL)w&fm`K_bRoOtGQC229!ZS4l-#bnV$vGyQhcjd zTYEtQJ+jukOr=Tafy|E0VZ^fstKB$E*<*U&9x|cNQevvhAXc#)ITH6mz zel8K-P)c@%hkc-NArjN#H|e>=b0S!p#c%T3zFAzWjB$nd z)%23KOctKA~qk2O%dndl8otK_vWt#5tk$%T^-7?I%@Hi=phTQ}D$;RcQ{!4`mnZSnlgD+^L*D*({q)glT{uy& zVR=C4`i(Cvvm3|}osokX3Q+1sG4-2lkuK!D9+Tpon=>+~4iRVvGX(w+)@W$58 zHqMg!`)F5KrW!nV)gOkZCq*Yc%I{eWY+sui)5`O`sD~-xDQNan>57tiZx3;Lo_Z$- zR}ZB_?z_QiSHvfKz75Gz8!g)%_w4hNKbG3L4U!m}t=6wbA^PDiK8tf)=(PP)?+06X z!IpYbiMu|R!?X8m@56V!m%ft<+H*@fQMP-G6}_jM`zV&r1ecfWKUABFPjZ!kBGOL@ntWQo z%MpISDUgk804d|(Jtf6`XyahsPW%qTD&yc^gxg*u6uz~F7#x8pFyB59gniLxJq`z* zMF><0O7cFy^WN=p`0w{L9^r>>qwWXzdZ_!DuceetVdKE}0fus?XOGIr@EIrj9@b!u zcQLP{+!&D#gTojfyU+^SU3x57c~;O+<#Id}kr_iQRWK9vm>_6+DX*Su&P{1A(k3D= zZ0CnWB7$?4_Ze~y|F^G_ShF+$1h4oYNQDw8Qx z@^m=af=?O-g28z!G*jr}GsptIH$(-JH_wAgoKpUMgUi~!2!5~C%6N@9kI_#;d|@;1&iEF zokqvXzT*O1=)TzfeD@?E0(=I$d2^x)r@RMD_z|3^Qc5B5tL^bY>b1VZLb>k(90(qND}bllyQQ&fFEUO=rKV`lijhqeV27 zj&;Q>akjc-%jHzZj&kmes$}~e?(6_aj<+tGjjVT;&)m{<{BbvXTqx;woHVJ7W zfZpoFNhfcN2zHbe%uI4}^w*fdz7!4j@eNTIGaD1a$V&w&OWK^L_CQsj=H;qMHC3UVk$Hd((z=%!vV=gk z7oJf#Ymb;3Bo~FhNxIOZf6~Mh*4XG8urF)+LEDce*8>gg{~H$Og9oddFtzoto=UIx z`N-Gx2K)xMs}8pA+4$+wtSxtQp@~Ubt?KWdiI!y9xLxzd8@T0C&uZj+1hq_A9YL^AVQW!%b|7cOSriHg10nVlJ|8WKTWYoV4t$t#58^cQUE) z@wlD7;NfIX=5fI#uRuP#h_?p*940m{DC%Ciwsc-qo6lVt#+$5O!=SaWZ*QzFXB7|p zkwyz${jseYz-bwkM5h3(Q) z^83;+c?A4{{{Q_!x%qkc%3q2a0m1(!#~M3W{a0USlm@h&)>3+pnp%rZjrXOclsi&g zSQa=(L@jOnKM9HzMHEs(64|6UB)t1(Cu_=OYBfbX1f;;RKpuj)pj(SSkWP8oTd+kN z*>qOy8#LMa9m4wQ+19SyN-kO*v-;><(i^lJ-d;aT^^VASjX9hhC!Z(2KRa(T$;}R5 zBY1+hGhrhiwimT2Pyw^A5d;vW-6@<#>XZxPrAlXt`B@X0DWP(jt{QKPcGDHgcj@fZ zQ_kB?MxPdW&**`p1VbUIY0j;P1& zYSPMWE1a38E<9y0nQc|4lFW-5Vc)ciHSb_jX*Am<3u)68Q3<8fY*}lYXf}F;N(c?% zmc&XHolm5QkwUcV=gVQzN|UM;*On)v9M*!!xud+Ms#t_F6>#jGompX0@6)@axgy2- zoouO(BJebi9EBq^supPyS=twhqs%vGu$QVvF)9#Rt&Eu1`gNKuO0@SjnBFw0)Tog_ zcrcME8K|KkV-KZ-#d1)kC^s&YYdEwO9g>x^$rl)`4yj8V+-o`2q)#j{8*Na1;#3${ zggTNhDP^pcXb&|_&l>g1KVGf686(u?;f#hNXS zLM&7o>*dE6?@by3S&A!2xqG8gtEiqO# zs*(^`24ka2&DlXZO`-V7QW;UO*nsraf7Bns=*qm$n0Ww5h>70|eU4J0LNl zk87A{{+S`a5fbyBlO?r978kq~?`zgAF7+gw1!vYtbxdnmsOh1!0Q4k+9ISQq|3#0$_lxzqg^+Q^qGUB zyn>X4md!G=sXU1sb4JggBm|KjUyj;M_KxzLNB&HJrRDf|z>c|vGSUCngcTYUr61h{ zcI7kiFo*moTO(0`j?^ufY7E2!pt`Q?SPZ!m;vhP>zNP3Zjq^mkWZn-3Fo)HnXwG|2 zZSK6XPF68<0egj%(QX`7T;4ocGqkRK-%?G}$FN}AM%fkm zMAPC>eTtyWOU*2>K9um?z?=-8wLmJ@lZ^b+2^A9M+diKa+4l4KxH1S=*#|==;Gi)^ zr>Lv@mQRZ|yywOM-cQ=L#Drl73LfU{AcAM?>H6J2%5uGXFrreRFMoL&2dZU!sgl9c z`3|*tVO?JHiGds0^6G^gm-BErH$PL}^S2tMg!yAcx_buR^9{TwUZUv*H8%ync)^C{ zZ~!4Y9amc}mOPI~IX66Ijp~PcD;z!2aMSnz&h6 z%@~eRg<&>!S49nqGhG^^+UK4oX%F9y8X6Db^cVPj(Ixt!WSiE-8js=D@^Pw-(ukYt z_#wH!vJa6B>s9a8SAbC70~I=q^X21wI#38kNxBm7aq;C9H6vRI>^X5NwbdFnfej2v z&FmjvaX<{#Wgkc8+N-0+r7!j6^NKLO%1B)b60l}g6|U*2GQl&5$13Y-a!K74HN(Jk zl-GeyLN*UAZ*J8pGU{ikNY_D?TkxHH72VWD;Bk8bfzu^}q2&;=IbfmhP6|2ORTm!r zs=>WFT9F9^c$nYS!L?8AI%Wmwoce;<*n~AkYLKmK0NQ{&SO|g&09nysUlZs2Qmzef z360&+JK4%NtLoFuUsJ@sj?(|EPg%84%xDjoER~ln;Jxm|AQR7ItmZ6@ex4O$e4A;; zvA9Gp9y>dR#D6>ce53267te0)P>z>x*=N*iYw0TF+RGidQi_balzfY zZ3rzZ+|7xXp5sTV5x}7K^ckbB=&vuYiIum9l&+-OwO-V%3P!1EJl0A?-aq}ZRYpGI zobrJUCOZUypl%c&=P0nx-Jt$BvQ&ryz&MCI7r~t^65`_(Fa{`68BkXrsOpa0@(b8x z&_G~6JIL1)f9E3Q3a0v$_@`_8#W9Z=6g6+cjp64&v9O90P1}d~7g~PO-KwS`Yzq0P z{mIbE5c5R+8Id5~`6rDlujUaPNs?#|6MhwLt^9W4n~x1&cB+%g=mPN&NN5|DWBfiE!V~s>VX4a8Xnq<#8$u;#VVLEfi%?FOJATQ7Kb?fS zbscw;cF*pBU|vD$-$F3}pD760dOXgl;nr=)Lp6+3 z?^%@Ul9cLT7g~G6_Yj>LLK7FM=Y%AO8vk;9_j{DwJxeB%Y1KsEjv2Hlu!Lr?I)Q6|0#qaKsRUdOU;k;0 zXE7ZnHy_N_VJ&z}=n03np++p&8CwTg4|roiJk=Zhb@wAJy};^}F$FI0!hR?BD2>=Y z6TgujNs?|_&ewP+=ry{Wva3g>6Nm|aP7J?;ij zOG;Rdh@!BKV$!N8st`h_ur1Bmj>|blq@snT!bUQ#H_Q}zgge!?a+TOBZ|E8i?>fgi z)iMyvE$U9awP=Ih9Art#GD9G8y?BA%>VEx2?L}D7C>6GaA~NKM@)StAP#XFCQ3@X zHrzm195s{HfCD4JK+bAZ&2ii% z+L)fEv#%j+%V1D4I6Ca!F35QFW0bxd`b;XWr%0S0l0Q~gkw02@K0_JedlT(Pxjdjy zLPru`vq=IqWBs86%M$E`(pE{wr?cO+Tk+XLD zL7Rh|$ih0ORrE#!ImPBcyYY!S;NG=C;kZo-`jNsPLJ3fA3G}!ksXz0byS;yY5&ht7yk>GG@0kU;lZ$=$GgH-1Ftl}1H$z=># zflQ~sNx{sGg?5qBpV$Dnc~UVOAi@x%0g7-CXA@i@)GFJIe*H(|5Om zufYF$xdv@<`^$d=v4qcV$sWCgq-RHb5WEtAyojuR>5;XKQo8x3t!b=5_uE5UN7jK~ zu6zeuO;*xajkKl!q;8xfVFP29y5>^wBbazf3uL{F0bjvOrJQp7ov+c)t zwpWA>TnZ}I;X}dY1>(#KGx8$L8~Tf7J4f6L&cYL^g%VxnweDa;>|vh64=1>heI%Yq zrr}nxTo`+Z#;$qOAcRy0jl{^O$4KK3VS1>y{{p(XX~y9z4TZXpYo~2;(PiBZ^liUn zj&6rS;6+?H{Mb}?IE1jTWhv?IrXa%$?XD2CxzY4Ti%qQWQxZ>MNs8)6|M`zzioHYB z-Ir1DEBY>h|BK0w=h4*Ls}Ah(=X~(wnT%0X#9K%nbP^Bl|Kg~^6%3K{f;5sd_@T%t zCAtg`huZZ7^X6}h>1o^ya-bPe-=`U)EL|cWxFpfwg_VgFTu7V(+6sxMdq&X>x@^rZ zJ>5Dszs&9XW=4FzG?sFcDR>d>ij|=IUK;fwc2@TsF~3@4@XV<4hFzBx+DM1+oc7P^ zdCy!m-eZ>CI~lmNB$3{Mlq2NSvt7ivPCcpj0-A7C4-tI>rI9myBTDH`Ab=RFXb%4d ztnZK?S$N_qkz(A$fW;V^58K--ge=4y4DM&pWDto`{qBW9PkpjqGsjqX^CBCenRbL7 zvEn0Nv*es{#=y&s9g^L5e+F86t)zKr7 znB4O1JLr-N+?zL7DH;sttt)at;)U0XFHE1~F%yno9Ov8C@ivOfi<;wJ-fngMA}^Nn z^@aP9|1wXU;|pVixJy^WcQOB@jksp?&8tAnzzbb}H72(%&UHxK(SLMv+Ihn3djB)R z4zm~8-MP97HDAf<*gp5Tf!@J8!14yWci;e0mVeY5Y9I;SH*iKN>)W|T4#D?*UdxSV zWP`qBjS4Hc60D4)$KE&?unJFkeh>l$t~h)ray-@EB2Gw-A81`U(2+5N`;cVulizH zX9kV!v+mVfraH%)H)G@TUQnub%3FU*YW(IIsh(F8Qe0{!1a3Udtx0Jz5B-6?F}8jwYTA5 zYM6GeG=)~X?ez^G_S<8tE8?B_`2%-ntTy|7u+5|G8TWx+Y<|XcI_oR%C>PJ?#PjF7 zmll_O`pdTE+;o&X*Sq@V^v8eBo1=0>-y zr?_T=>3wmJyp<*E`?}z@M9=o?;-)wI)YiI9d{+Bc38v5amT*2zwZ&unzHVeCfAM`N z-r2(cxSi}{2UopvH`(@mynY?2zxh7isP#I^?|r|TuLK zeXrNyXD=^qPVZ$S{I|>AHfJsSrQXlHqi;d;&oeqUzfLFZ>zU(1@5;R6#9i#p`rF5s z|A#6M5J(kmF=Z}4+Bxq;I3syYmO9tig%7lW!j#}4xStlq>6Qm!pp?<~ITiA0}s zQmotsoi@LZ*+so-%_h87ZpGzf#3J0}f^Le6fhK;h+q;p-HD(!X#h%pIA}9L01WgervoM8vc&YSRiuY7`htcE;OWOmWaw&LnCi(aC5iyl+bju{1^M z`&{itq-Q2f!EhVhZWmFDh4YR5LLtlA<%LR7542Jbq3(FQ9gsvXPnvYiZkwZbg?w`o zwWpV&52C@yg~W{ucG%mik!aq%GPHFQPpRI`{w;-k!Y;G10*1NGCGGx6wt|tIT&#wC ztjRR%$JH7&Nmgp>7^uk3#^QjrY)b59yBf_aJSM6&#nvxwSJz=lSFN94)aQRJUMU$# zng}`CafukY=^5I8lM=M^!1oOpIEfKb7=FJZuoUorc7p*R01~7S1PiFCCqqL$jn~sbOlE~GRr*`_%c#lUYeTc^l9pr}a=2b(V@{Y3oJ)*>xa|^|N4r9-wOnLK|88Rm6X?2b zwvcse(B5ElF~?J*!EV)RH4gDEi_lKRCy5hCAP$2cVL6VjmCe{&+g&+IY6&9C49;e+ zP4Sdl@U^N;TE=98vA0`I&vqXb#hGmLuCO(PSf^nMlTYHpK^+n-q*al^GTe*xGi+&Y z{hK-OvMe66IYY)iz}wihE=*ft3Xuy$k?tn56!wQu2e7EAHrAdVyJG1gMULRkRGOaD zbd+$f+|De_eZ;$nI%baV+8_%Le z5-ZGd;uibj8T^~HiwRkZk*1w6Ju!1u3{rpjA6;(oI5Ld1}i*7zO=N|KT4 zmY@11lK zpOFOAa1(^O>nmhnalVYQ*75$cP2+!i1Kd!((BcVjP1Fhfgqe;9I086Stdxfl7!ZVE zU*j+y#YNIl16BZaRjNW6n4alH1yNIkuo0;z15YRVwE0az3SJHv1{?}DaTG0R#LbR~ zSGWfdw|4&M7D>(f5tV*MQzj)TDc$=a$>K`bkJV|b%9RS`h1daswgGUUq6;*RT_ZpR z0U^%UgOnQ*_4XU&Z|;PGawi2bz%Aqo7-iISdF}red>)z^_;=hCJ4n zrg~8eamI=1E3=DOm9`il6hsU_a7KK+QdZA@d)K~&K|zndbQ6V;h)9BQ=b}zzqLpY% zZ2D9FnwEmmH;GJ=k4HfVrp7CvP(ElJk_4Fi0xj)cY_7@}T4B_$#6uX2!ysyf)n(_gDAG_?XQ(R0zT zN)g?v2x}w74J?MJvwPuvC{=aYPhgqb-U4l+@HjH#L-{u^C~D+=CJqK6Y|KrST^`6) zv)0v^yc$V*s@x2tRb<(5{e%c1&wueD$iDJn7QR=I_NaI0z-qv|l2>TRyA~DWsFEeJ zgcvp`vL(~W*)6+^q>6*2yawo+&;^f#V%Nfo>ZqNE&JC-eoXrvTy+kf`LO7)$5+O>U z+ym?p*;TWEp*g5r{4z4tB`JTx7=@}Mi#o7gtwDS&&qT&Il*s_;^aRkGNQPPYL z0_Ww{eE)zdkj+cd(BeoJ#k@kwy%kiX2lPc%Hj`C6u!pOG!WF$>M2az9cOuX7(m?*8 zPeq&h$`CdoRkmJu7`!Wt(!A zmdSe5=TnXLQ|0CodpLlf5jSQXZ%e(<7IO((o~I}KCvZx>#lH}C)P@>h^07-;VV}KY zoyQu-;&F2%IgU-n{pi13yWMZJe%ZY`t59vd&-VXSEcaD-UcB6}+sy>0>v>xCp7;oL zwZ+nGy8csjGfkYjbLnof@N7uS?fE;8B_F`j^1J_vhM#WU$A=1rD`U9uxq90!Gg3En zT_+c|g~e;Rp!i=8W39L7bUa9(%ika$>*7B?e}^;SH+93z&}*GYa(x_c`xj$h=fv%lV;>r{0clPPQwni`O7Oea^U-o3Ob> zelnzN&wW2~Y({h}IvswlCNHy>%`p9R*TY`V#7i^nY^?9i`E<12*LqgmT*rj_Arte@ z*fj71-`|W(m#YXq-vvFr_t({(i$pow42|X)wA!xc=MN%Y@XL zcrp#l`Nk80W3K|!C2y=euJkXGrLlB%InPzem$+`IKjg!4jjOU((M~B4Iaw>li?Y-9 z$V+4GdVd%XJ!b{J;xOT+rmbr))`wQU+zl{aPGQ!s(~i)U4B)z3`#(bWN_)I&?QYgt zPl85UthM;fO!TddF=r5Y^xBmkdo0i17`JN0ZUJ^8$FME%mhlW& zp*tAl)n7g zLE7lAgN5VR)ccqI^*PBbmGZ^BT<1I+lMr05&?2-l=bR*{KjX>ODGL(&xcTsz zbMn^R`_g>FYk%$pmY=gDb5e?zaeqlB6we_e@(?~z$gvV9ZuvMYioRe{ujODUs2BA`^&sJ4jw&vhHN~1zUZcsbaLS3!e z-p|#!RkFaK+5Cqpm|pYhy1@`DXU&)^=IYTlaEmL-Y>9zoCp`JeWZ`$3{aCYlCmk$r zA8No(xk%>eY%*$wIkC?{46orzF-=L^SlHXBv&5*HsN{Y=$4k?MY!Iljc)4_Q8*}lP zaK^An$#5CIq+*vY{6AcsQ*s&6@GBC>{~VJ~|9Y znU1n394K^U=p+uEg^?G9=m9eg%$qjFl?IG-AVK1}N zo`o2a@TVwe?G)6FHxD9JVd#cpvMScY)U9b7w<(xbW$Jn(5N>3z!Y;=FJkqVATmk;30jgnwI@(|Jhd=L zp0-xZPA60aeceI2Q~^ksZmyqn_5ey;iEo?3#$kxtPZaIb^=?=i-uQ7j@{fFT+Ppo9;}tlg>zQR*2U57WILfsK zzCs#IM@!hq1xTL>LhzwINaP{ez6}75i<9O4O=~O_qYu;pNis4^g-|#hMT?Sef3T&9 zpgS+n`&MtkJ>roKn5Gy*vb!K6Bzww;_IM_gtL6>}OG;a; z-Y#M=G9+=UHk~WwJj34LZ#}i25zn8BDjnF+K{q1OFfmyQ2Y>oH9eX0j0vOan`Sep^ z5ds4qa@bvox|!f4utV6>eikHf0Rnsaq$on!P4Rcl#zYi49Bnbdij@CN?>2$K)QSxQTJxur6q!C@vpQRVSBXjTRr;-0^Jzks<5RY42jg_Fih1TX@Hu+tM~^Qym%fl zO$Y`XyFY|J30A+g)AF^`_O!p?L)_5#QQj|oCwK|TAYE)Ret=fJ^Jm<)@!u)y=&#Qo zdTYMVIzG4D=zRUn10Llg>k&Hm9~D}2;_K+JzQJ7P@71pG^F=yt3mbR1zZY#O+CDd0 z4pVKVKNEO9BosG4=2dOB-<>aO@xNaKJ$;Qk9VRGrzs^Gk-dZYSRV`aA0z*Sbe~a&T zBE_$A50sO)4E_a_!Ap5{4c|iZ5OpV-y0v|+s=`>p9e>G;xmvtpJQ*q!T3C9az0=1 z*e^e~^}(7C>Q3`?jZN7wFI>pi#2fguTKpRWbMmz!W$q+A=;A`TUG#9FK08S#oK`d4 z8+s~Fe?a#hY^dGL5FZDRovd!VR4Q+k&Z^1$lic4gOZAsFxd#s!&mIdAnR6 zTAfX93csN)^4Ay-H-%5mDUxyX<)1VQ?iVsY6t{)SWoZa@u}&y49c_v{nYojDpGz}J zyXH=xE@-%L>UnNEY2|eUv_IAx8gfP6d6!z%Sw?YKSRG)r`Ph{9mY<7Bt5fG5)W1!3F?; z@IQY!XB+eXw3AdUOr~6{$Q0^`0nC{ zG5KV`|5tHjBK>^@(;uNr>kI=sWIB5HWx%0najhyFV83gyLb_}z6Si@4G#92nU4xh*wVVm=P%XBAk~Zr$|L9w^B1kd; zgXNj>-ip(TMMdrJTuieq9*>UvrQ4am#rw0|`w>*8mtH~UE=cp>Z27jTKY4*<^K|(@ zXbBm-D<#GKk$Tr3gE*OZ3=BMaRp{iujA6*A90`&7@)jzeaZ8$0YK&>-$?Yg!$r|B% zEg;VMU<^T@nc{y;s010`?<;+dCWR1kt6!%~%@s1dxNR;}BJTrn26kLzJ1g3v zGwcCCD%PfLVirhO3hF_EJ*)vaOpPPr5992XOlLAi!h~gP;pP+}-%7Mq{nL3M$6=!K z{;y9SIpfW9(Jhi~yNQyTZ#lNatX4s_YZiy5K$2-k+X@g^uqdE${uAVZvORIO@60p; zfctHMC}SDW=MSQVb5%=IREs$f{TA|Pdkl2urGWn5k)pq5yz1Yp7P344gVnrt3U?4XVfwrntDr)sT_K1 z#?;Exis*gBuv8FSm9!MqfLOS$f%ZX z2=$PdZ>g49XA(0M>sI~-$E8wGhl(8e(sCh%5`m)9-u8a`E>!#A7O{_sWUJc+=h=&E zxqyge2HfCE4I9c`CPaudE68hm48e1_=Q);$>S|`nJ6E&1#SpDsH#pdeR8fv1ny?pE zEC3PRxVwGaIkv(N+7`1uH0ao~rFC22t!G3czL{oje*#0jx*|*|g;z>aJ(`!mg_Sy{- z(t0$Pnc8SYe^S@Vd{kfc?y#gw4(1xgXmg%@Hbmz&XwwnR85zg5t_)wTxU9P z-7&!>2{WbDU&L=UHM)a-KX|A*QeL^Cj`Ug!%ep?B_Be`p3eWU!{{+*_G}hnt9mD4N zJulf>bud7L88drS1;t(Iy}}Vg2}R!|_pz$Iuq|p)vQQ0|Q&Qv*G7CKBP855rX1l?1mZ9W%$EWlUAew+rMspZleV~;PJlH7|^c6QEoki)zo+AkuA zOx7>O*peaEZSgSs&=<@16SdWfGu0HdlEPs6I=jR|-?a4D9r+b~C)Ho#$C ze@3fsb@peFh5I86N`Tf<&nNnSe8vF+we6~n$pW7=o2O|prat}@S3Z0b#{bC(yPbII+S>`1pe=O*%!`J! z?$-ufvkLHU2&|WOIRkr$E4%i|;bb*Ut@goL2mDf9PLRcQRYx4j#RHT0Ism*GBZ?bq z&>CRVi`dBY&R)3IRN>pq02yGwklF8Ua^vWkM#&R)rqd7<5I}+=k#byA25=)aLI+iC z_DC(U4ILAS4>yrWUC{*GsEXM9I84SSUc`|_<47$~{nsXzoiWW$*spU<4 zp%;xo!g`Dm$w>rB2fo>Hw@K5+5B`E@rwiE9GTG%C?+M*Hf}2gQT|cyK97zje0;OlO zFPf`IG`ZfCoK6jHlwB={&D^PO41{3R+x&$P;00-( zU9mucZ1Y^E&Ig@dxNhHvWTP2xWynX-+$N|898edEo6Q|E?~f?X!=SaE^a5C#cP90G z5~sO?3wPGgx(gGJxo5gjDYeV#rYNt_2tzYY|9wo==xRg~p|i3a7%Nv2vPWnY#i3nN zFRr>jn{n^KhI5XJxu4i>*w512RRi%Se5WhLF4|7ir=XnuU?C~^uD~D~m6#+($^lxk zp`wp~X3UF1d=bxspe7eJGi*(}K@blXVeGY^xa;{RT)HQgd6+tpK;2Cdp73b2{Bmr6 zQ)rwHcjzFU37*pQ)%jf6zZSUg4z)jDVLPJEykOg*@njv^^|6na*nTecCk+4@o_Z?$ zS5F?e;P!rZ?9mYt&B#5)coz{8lC=_-o+6j9L#@*!5`91;|9V&cgOkN6SBq6;|)<3LgceUPJnY@c2J< z*2a+pTryc{$I3+5(hDpOEv+xr0tnab{Wja+b0+%|KU6$J3I=M@3Y60el6b@NvqeKGauo+0}y5ouLH-uV&sIz$LF~B*H|LF+io%XY!sA>_cF#7 z@vI-nQ!1SIS*YR=H;sUmOjWqeR)vR7w!8f~fv<3}yt^vg=g8yT&Y>8wc7)($B8xfu zBxE@M#E{mu)vcTDX!D%HB`g#8;mEf&78|^q+@2gnL_qXEU;+Xa$pc&tSOaMTbQr+2 zRg*Iwx+4zj1C@Hn=`SMuZrZ9mNWy?0XhO5Nz^-xQXrv~_BSZKl#^TStvCj-^@nu~~ zY2N@s#oePVNM)XW*fNVkoFJ>pVFSd|(v22u+vjm0+g)GKp0d zDAE=5@{i00m&BzrYe#~bXsIEJ&3EN1lt^$T6KQwj)aZshTD;33a zKamwXS%(nW3NS}aMbq&wD80>6b-bjQuJRo=MLjgVt$Hd@H8;SM+088zweTv<&~P1# zzf?zZMTe!y$(A~d(vo~ea$jE}3^*rNH8)tt z5u6)Pmr8K?81@Qxk=^jzaLH%(Op#ic{sfhzwV91%T1L?jw4oCq->pDaWK1T~#m_!< zDKYRjo4Ndf*;CQ2uf7w21bzKuC;&GmEckHS2&{Bg2&@v*l_yY%!Vqve`j(=_Xn}m*cae3zab7OUKQe3{5iyu3CtsFY0avl$YMlSo4%@fkqf!Bi@7r8{eF6JIl9mF z$9Sm1dq9S!5S8;AN!bUnFKqG>%2{dNg(<_KIhVboS4VZbldMc824CHkja+-9wju)^ zt&YU0Pgu1tC?dN4HM50=fIDH0 zH;qrP2d>mM^EN@P4%$p#ou}Ro^*(1dKRZG9jM&h_>;q4x#$q7XWE3;}*j=afH;ym! zG4^XF%io1oIp(DYOY@hPmB^E2SPe@W)k4ZSFXmK%(sp#6PXW<`TKy4CGYopS+D2Ka z&Y}nOaG(jDbuynxr!=-y1b$`LQD7a_c*U#kM#gA(Z13~-Z$)mSPC&F;@t=ADuWF0sa3ffGozyM`6Hqz~tBC9}tsO|YNp-5Z_OTZh6O)vmkqnc5W1mMmO5PT=B9uN!2P@6K7+&DkfbS2y??y7(Zr z6@6o3;lA_X&c!JIi0Ct;QEq-od-?Ncn#MTKIpm!4%qS_Db%~ZIt_$E`B$qESwGJ`z z4`9W1Xhm+|XVvu1;0gHa=TMki?%sQ6YCTPp=`TKjWZR$>Nl~GPG;xnOeIJgWhr~yM z`d;#tI{OEy7fuPCyWl}rfx6#&{gW5hDzqhB7n%I(JFUFhHZbo&w{ojz?rp>23AyC? zXBhQH5#Lu;M}E7FhVJYW*Dfl2=loL}rD58an`FC@{^Ap9pPlUX9#5O|tXEn18tz># z<4Cjg&D`k}Ke_s#;k}1!W_n*o?ka-}Ca@gKjh}j(B#sY&DwmK4KPGI45N~Xf?M`9- zQ#kfwjwRSrkSt%oBd+8QWlP>p^a~^W7O{kF@KHGXhmM+$K)ollieDe)(@o?Pu)(bV z69)O%6j^p=ktO6;g1mpuEcnUfY>2h98^SjS`z{38OPttO%Jwb5;sM)}JEAXe17nlo@_Cn zc=tF?d+n?#d^uN$DRN_~1S`>w;{=u|1mhOaXt3g(kW141Bw8Hs^p4zfqwaaiF4^NX z)I}e;J{_p}xaz*H9~_@_sT#d?k?HfVL?$}L_w!LgNiRo$H4d8j6(RBK`|r}BS0ihGO&ZhDNXJ$m^`YVLa!2pRN#Q33^z*SOQXm!F6xi@ zufggVBRU;9+C;XwETP9DUYWQwKG=y-;h%#I&RpZWa1LW<{DE;dG6W8IexMyMBIWP% zfPe&vP!Tfe>D33?9-5rBMoYE=V%$$1Xfl^Lm`N|i9!yOW+!DJF5H(qXDanvg zs=zwLlL%jb&VIUbiXuE@kgtI*Br-maA&v`FF%*`@mrIcYRI!x9l%4~O3XwL?OvxE* zsU*-sc?`n%iM_R*SKNrln2$$<;snPB1|m68+#75$#&2C6L1FLhPaS@d=|T4hI8I;y22#eiv0qHlTavn=!3&+Lt`LyiyMTnx9=9E&r3sLtLffx-}4+O9ePP7+7iO z{sc8Y!N?boi3hUd-!jSK0bOpGW#>D+ogq?qx z7D#e#{mZNsN+gk7-mJ$IEe*0mP0${JPMSyfgHPNC`;@YUe`%AO17zl#uwSKtk2&{As}| zRHAIFQ$;5k3xOuE`SS}M3YU7abB#gOfCi`tTQVMUCyti|FL9lfV+3=AGug-P9QeuG z*|5*bk5~o0fkLnpZt0KPKbGe78vUAc4?(BEgAW3W8IM4sI5NmhEDG|Ed_kwsgBk?Q zOlP9#i0_z%3H8rlGB%=#qM|oaqt*Ue@J9TJIt71mfj#px4=I`d`Qg(NP`)pV^x}ii z`3qpv5)*~vpB+q-+tG+WOWA2cn8mH_0_duT@RK6Qp{Ov0l3K#x7{694Wm~#1oCc0A zz(dKmoNu_h&Vo1eU5TXETYP3~a&pLvA}q!pShdA)fbrF*BkxtHgD^lw0WbKq`L_kS z`_=35q@f?YBV5Y7HHCpP=pHr$AuH6frr{4G(CA0;t6@hGZZ=~Gw*q1aUpEQkfGp=k z_`-dWgq~1(r;neAPO5`1LmvD9K11yz)X`zc`CQy#L81MQC8D?i(P_YaTL{RFioD_Z z9;@hIBxGn`UwvTmTz?0Po(YxlLloUG95O8leX!MVR3;!EV}U$z9m&2KmHCko64OMY z2*2x5Tyft2&>ob3iYvJR6*EJA!PVhdRI`_FmJsBK9Z4IMD7{)s`jQ>_rrys8ed4WJ zQT@PE@POa()V*Qo0z4DGqsyl~x*!hIfKiM1J~$dN{=}B0k%sYuYKrX@tDBbM=;3e98SAW!Pp9avQ}S7)TICFtE)~_^daM98 zOeZSMm+R*&l7p_3y-ZFI-FgX9)zo)n3LH1mN{gKekt#(e(+q3DY*U*u9?!+n5fgr?aXC^3z=Li2L4-e$KIx zmvlsFUu&An_A0(gO{NU$VmM%0d}sNYENgrRKTzu~Q^9BFVQqeyS0H-Sy-|3O>)YCN z5+2h3bQS7lZ#`1@F?Z4u=1e_U@7n#C+q1t_6WKnN2_H;bXUqFAwH89G1RqKR6-md0 zKAKNDu6{8H*|puy+8`gUD?j@dX1iN{gd4&CQ8h6>d?lD&9hou;xzK3=AD!jh{ZmRz zq)TCezTo(jb}bIvzk%5zJ(kTO>c~=Y-9&v5h}FC@g|p0^Kgf0NF(966rP1R3B{lb8 zDeQV}v5|#X9!%Q1N$oYU}=U z^Pr@P-xS{k<(((O?6TW&zy0CJG*@cVm5XXFjbBG&Vaij~%Uf{qF&6knw#JIz<8*W5 z?!u*7<8PdIrL~dM(`3+;XmIhu_McXM+x5qp0JNXRfquT?Kp!>xvg7r^)_Xx2W6<=k zM`|<>PK)i#?rJ6%fuPhCtVCKO{jj#wo&IHZRn_et?YXYq>XxRXq2-%M8x~p$H*2>J zbaC;Y9KLg#`A2Hgi-_wd2zpsq{9M%slI?8@S9R_ZRl_(3BFDj5chTnT>ZHR0+t_Wq zczz$7N_d=^WV{IMEIlY36>jE(3mMYbzgO2BTi;Ha37tmO)w*NjAql>=++{&Ho91IS zQ5r_HTJ!FQy?da6@XF6-H>OY?l%)swqLol^|Fm7}2jHBqmiMEFmQPwbh@yw^H(F)H7=9T8`eQoowdB~2R3?&NNMObS6!4UspWhlVmRnjOED`RYE7`LL-NHdWVPKK zT0W!Gm3(0+bh>Q)=2lD%T{^&VYjR+|DjouC3UlBhUwB-YcE5u5dn?{n&R_V661UO%dDp zz_>$CzWbOPuVD5!^p3)8d6-XR3A-a6MqnR!!|$3nOg9B zoAFnOI=#arE_DVE+cWK_wsH0N2~$5`ydxPea?^b^5o&!*zUP=@a~!c5zIDUKObJ)9 z9%n>p`@Qk4Ko{bwTi^=|THxmIDK