├── .github └── workflows │ └── tests.yml ├── .gitignore ├── .gitmodules ├── .travis.yml ├── Cargo.lock ├── Cargo.toml ├── EXIT_CODES.rst ├── LICENSE ├── Makefile ├── NETWORK.rst ├── README.rst ├── RELEASE_NOTES.rst ├── bulk.yaml ├── completions ├── bash-completion.sh └── zsh-completion.sh ├── description-pak ├── docs ├── Makefile ├── build_commands.rst ├── build_steps.rst ├── capsule_commands.rst ├── commandline.rst ├── commands.rst ├── compare_to_docker.rst ├── compare_to_vagrant.rst ├── conf.py ├── config.rst ├── config_overview.rst ├── container_params.rst ├── conventions.rst ├── double_bridging_vagga_networks.png ├── environment.rst ├── errors.rst ├── examples.rst ├── examples │ ├── build │ │ └── gradle.rst │ ├── db │ │ ├── clickhouse.rst │ │ ├── cockroachdb.rst │ │ ├── consul.rst │ │ ├── elastic.rst │ │ ├── influx.rst │ │ ├── kafka.rst │ │ ├── postgres.rst │ │ ├── redis.rst │ │ └── rethinkdb.rst │ ├── doc │ │ └── sphinx.rst │ ├── misc │ │ ├── certificate.rst │ │ ├── firefox.rst │ │ ├── flaky-network.rst │ │ ├── graphite.rst │ │ ├── selenium.rst │ │ └── travis.rst │ └── tutorials │ │ ├── django.rst │ │ ├── golang_minimal.rst │ │ ├── laravel.rst │ │ └── rails.rst ├── favicon.png ├── gitlab.rst ├── index.rst ├── info.rst ├── installation.rst ├── network.rst ├── overlayfs.rst ├── pid1mode.rst ├── requirements.txt ├── running.rst ├── settings.rst ├── sidebar-logo.png ├── supervision.rst ├── system_settings.rst ├── test.rst ├── tips.rst ├── upgrading.rst ├── vagga_features.rst ├── vaggadomain.py ├── volumes.rst └── what_is_vagga.rst ├── examples ├── clickhouse │ └── vagga.yaml ├── cockroachdb │ └── vagga.yaml ├── consul │ └── vagga.yaml ├── elasticsearch │ └── vagga.yaml ├── firefox │ ├── vagga.yaml │ ├── vagga_webgl_intel.yaml │ └── vagga_webgl_nvidia.yaml ├── firefox_with_java │ └── vagga.yaml ├── flaky_network │ ├── app.py │ ├── nginx.conf │ └── vagga.yaml ├── gradle │ └── vagga.yaml ├── graphite │ └── vagga.yaml ├── influxdb │ └── vagga.yaml ├── kafka │ └── vagga.yaml ├── mysql │ └── vagga.yaml ├── openldap-slapd │ ├── init.ldif │ ├── newuser.ldif │ └── vagga.yaml ├── postgres-alembic │ ├── alembic.ini │ ├── alembic │ │ ├── env.py │ │ ├── script.py.mako │ │ └── versions │ │ │ └── 360aff35f0d_init.py │ ├── app.py │ └── vagga.yaml ├── postgres │ └── vagga.yaml ├── redis │ └── vagga.yaml ├── redis_alpine │ └── vagga.yaml ├── rethinkdb │ └── vagga.yaml ├── selenium_pytest │ ├── test.py │ └── vagga.yaml ├── sphinx_doc │ └── vagga.yaml ├── travis_gem │ └── vagga.yaml ├── tutorials │ ├── django │ │ ├── .gitignore │ │ ├── MyProject │ │ │ ├── __init__.py │ │ │ ├── settings.py │ │ │ ├── urls.py │ │ │ └── wsgi.py │ │ ├── README.rst │ │ ├── blog │ │ │ ├── __init__.py │ │ │ ├── admin.py │ │ │ ├── apps.py │ │ │ ├── migrations │ │ │ │ ├── 0001_initial.py │ │ │ │ └── __init__.py │ │ │ ├── models.py │ │ │ ├── templates │ │ │ │ └── blog │ │ │ │ │ ├── article_detail.html │ │ │ │ │ └── article_list.html │ │ │ ├── tests.py │ │ │ ├── urls.py │ │ │ └── views.py │ │ ├── common │ │ │ ├── __init__.py │ │ │ ├── admin.py │ │ │ ├── apps.py │ │ │ ├── migrations │ │ │ │ ├── 0001_create_superuser.py │ │ │ │ └── __init__.py │ │ │ ├── models.py │ │ │ ├── tests.py │ │ │ └── views.py │ │ ├── manage.py │ │ ├── requirements.txt │ │ └── vagga.yaml │ ├── laravel │ │ ├── .env.example │ │ ├── .gitattributes │ │ ├── .gitignore │ │ ├── README.rst │ │ ├── app │ │ │ ├── Article.php │ │ │ ├── Console │ │ │ │ └── Kernel.php │ │ │ ├── Exceptions │ │ │ │ └── Handler.php │ │ │ ├── Http │ │ │ │ ├── Controllers │ │ │ │ │ ├── ArticleController.php │ │ │ │ │ ├── Auth │ │ │ │ │ │ ├── ForgotPasswordController.php │ │ │ │ │ │ ├── LoginController.php │ │ │ │ │ │ ├── RegisterController.php │ │ │ │ │ │ └── ResetPasswordController.php │ │ │ │ │ ├── Controller.php │ │ │ │ │ └── HomeController.php │ │ │ │ ├── Kernel.php │ │ │ │ └── Middleware │ │ │ │ │ ├── EncryptCookies.php │ │ │ │ │ ├── RedirectIfAuthenticated.php │ │ │ │ │ ├── TrimStrings.php │ │ │ │ │ └── VerifyCsrfToken.php │ │ │ ├── Providers │ │ │ │ ├── AppServiceProvider.php │ │ │ │ ├── AuthServiceProvider.php │ │ │ │ ├── BroadcastServiceProvider.php │ │ │ │ ├── EventServiceProvider.php │ │ │ │ └── RouteServiceProvider.php │ │ │ └── User.php │ │ ├── artisan │ │ ├── bootstrap │ │ │ ├── app.php │ │ │ ├── autoload.php │ │ │ └── cache │ │ │ │ └── .gitignore │ │ ├── composer.json │ │ ├── composer.lock │ │ ├── config │ │ │ ├── app.php │ │ │ ├── auth.php │ │ │ ├── broadcasting.php │ │ │ ├── cache.php │ │ │ ├── database.php │ │ │ ├── filesystems.php │ │ │ ├── mail.php │ │ │ ├── queue.php │ │ │ ├── services.php │ │ │ ├── session.php │ │ │ └── view.php │ │ ├── database │ │ │ ├── .gitignore │ │ │ ├── factories │ │ │ │ └── ModelFactory.php │ │ │ ├── migrations │ │ │ │ ├── 2014_10_12_000000_create_users_table.php │ │ │ │ ├── 2014_10_12_100000_create_password_resets_table.php │ │ │ │ └── 2017_03_13_105849_create_articles_table.php │ │ │ └── seeds │ │ │ │ ├── ArticleSeeder.php │ │ │ │ └── DatabaseSeeder.php │ │ ├── package.json │ │ ├── phpunit.xml │ │ ├── public │ │ │ ├── .htaccess │ │ │ ├── css │ │ │ │ └── app.css │ │ │ ├── favicon.ico │ │ │ ├── index.php │ │ │ ├── js │ │ │ │ └── app.js │ │ │ ├── robots.txt │ │ │ └── web.config │ │ ├── readme.md │ │ ├── resources │ │ │ ├── assets │ │ │ │ ├── js │ │ │ │ │ ├── app.js │ │ │ │ │ ├── bootstrap.js │ │ │ │ │ └── components │ │ │ │ │ │ └── Example.vue │ │ │ │ └── sass │ │ │ │ │ ├── _variables.scss │ │ │ │ │ └── app.scss │ │ │ ├── lang │ │ │ │ └── en │ │ │ │ │ ├── auth.php │ │ │ │ │ ├── pagination.php │ │ │ │ │ ├── passwords.php │ │ │ │ │ └── validation.php │ │ │ └── views │ │ │ │ ├── article │ │ │ │ ├── create.blade.php │ │ │ │ ├── edit.blade.php │ │ │ │ ├── index.blade.php │ │ │ │ └── show.blade.php │ │ │ │ ├── auth │ │ │ │ ├── login.blade.php │ │ │ │ ├── passwords │ │ │ │ │ ├── email.blade.php │ │ │ │ │ └── reset.blade.php │ │ │ │ └── register.blade.php │ │ │ │ ├── common │ │ │ │ └── errors.blade.php │ │ │ │ ├── home.blade.php │ │ │ │ ├── layouts │ │ │ │ └── app.blade.php │ │ │ │ └── welcome.blade.php │ │ ├── routes │ │ │ ├── api.php │ │ │ ├── channels.php │ │ │ ├── console.php │ │ │ └── web.php │ │ ├── server.php │ │ ├── storage │ │ │ ├── app │ │ │ │ ├── .gitignore │ │ │ │ └── public │ │ │ │ │ └── .gitignore │ │ │ ├── framework │ │ │ │ ├── .gitignore │ │ │ │ ├── cache │ │ │ │ │ └── .gitignore │ │ │ │ ├── sessions │ │ │ │ │ └── .gitignore │ │ │ │ ├── testing │ │ │ │ │ └── .gitignore │ │ │ │ └── views │ │ │ │ │ └── .gitignore │ │ │ └── logs │ │ │ │ └── .gitignore │ │ ├── tests │ │ │ ├── CreatesApplication.php │ │ │ ├── Feature │ │ │ │ └── ExampleTest.php │ │ │ ├── TestCase.php │ │ │ └── Unit │ │ │ │ └── ExampleTest.php │ │ ├── vagga.yaml │ │ └── webpack.mix.js │ └── ruby_on_rails │ │ ├── .gitignore │ │ ├── Gemfile │ │ ├── Gemfile.lock │ │ ├── README.rst │ │ ├── Rakefile │ │ ├── app │ │ ├── assets │ │ │ ├── config │ │ │ │ └── manifest.js │ │ │ ├── images │ │ │ │ └── .keep │ │ │ ├── javascripts │ │ │ │ ├── application.js │ │ │ │ ├── articles.coffee │ │ │ │ ├── cable.js │ │ │ │ └── channels │ │ │ │ │ └── .keep │ │ │ └── stylesheets │ │ │ │ ├── application.css │ │ │ │ ├── articles.scss │ │ │ │ └── scaffolds.scss │ │ ├── channels │ │ │ └── application_cable │ │ │ │ ├── channel.rb │ │ │ │ └── connection.rb │ │ ├── controllers │ │ │ ├── application_controller.rb │ │ │ ├── articles_controller.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ ├── helpers │ │ │ ├── application_helper.rb │ │ │ └── articles_helper.rb │ │ ├── jobs │ │ │ └── application_job.rb │ │ ├── mailers │ │ │ └── application_mailer.rb │ │ ├── models │ │ │ ├── application_record.rb │ │ │ ├── article.rb │ │ │ └── concerns │ │ │ │ └── .keep │ │ └── views │ │ │ ├── articles │ │ │ ├── _form.html.erb │ │ │ ├── edit.html.erb │ │ │ ├── index.html.erb │ │ │ ├── index.json.jbuilder │ │ │ ├── new.html.erb │ │ │ ├── show.html.erb │ │ │ └── show.json.jbuilder │ │ │ └── layouts │ │ │ ├── application.html.erb │ │ │ ├── mailer.html.erb │ │ │ └── mailer.text.erb │ │ ├── bin │ │ ├── bundle │ │ ├── rails │ │ ├── rake │ │ ├── setup │ │ └── update │ │ ├── config.ru │ │ ├── config │ │ ├── application.rb │ │ ├── boot.rb │ │ ├── cable.yml │ │ ├── environment.rb │ │ ├── environments │ │ │ ├── development.rb │ │ │ ├── production.rb │ │ │ └── test.rb │ │ ├── initializers │ │ │ ├── application_controller_renderer.rb │ │ │ ├── assets.rb │ │ │ ├── backtrace_silencers.rb │ │ │ ├── cookies_serializer.rb │ │ │ ├── filter_parameter_logging.rb │ │ │ ├── inflections.rb │ │ │ ├── mime_types.rb │ │ │ ├── new_framework_defaults.rb │ │ │ ├── session_store.rb │ │ │ └── wrap_parameters.rb │ │ ├── locales │ │ │ └── en.yml │ │ ├── puma.rb │ │ ├── routes.rb │ │ ├── secrets.yml │ │ └── spring.rb │ │ ├── db │ │ ├── migrate │ │ │ └── 20160715112354_create_articles.rb │ │ ├── schema.rb │ │ └── seeds.rb │ │ ├── lib │ │ ├── assets │ │ │ └── .keep │ │ └── tasks │ │ │ └── .keep │ │ ├── log │ │ └── .keep │ │ ├── public │ │ ├── 404.html │ │ ├── 422.html │ │ ├── 500.html │ │ ├── apple-touch-icon-precomposed.png │ │ ├── apple-touch-icon.png │ │ ├── favicon.ico │ │ └── robots.txt │ │ ├── test │ │ ├── controllers │ │ │ ├── .keep │ │ │ └── articles_controller_test.rb │ │ ├── fixtures │ │ │ ├── .keep │ │ │ ├── articles.yml │ │ │ └── files │ │ │ │ └── .keep │ │ ├── helpers │ │ │ └── .keep │ │ ├── integration │ │ │ └── .keep │ │ ├── mailers │ │ │ └── .keep │ │ ├── models │ │ │ ├── .keep │ │ │ └── article_test.rb │ │ └── test_helper.rb │ │ ├── tmp │ │ └── .keep │ │ ├── vagga.yaml │ │ └── vendor │ │ └── assets │ │ ├── javascripts │ │ └── .keep │ │ └── stylesheets │ │ └── .keep └── weblate │ ├── .gitignore │ ├── config │ └── settings.py │ └── vagga.yaml ├── fetch_binaries.sh ├── install.sh ├── path_filter ├── Cargo.lock ├── Cargo.toml ├── src │ └── lib.rs └── tests │ ├── dir1 │ ├── dir │ │ ├── subdir │ │ │ └── test.ini │ │ ├── test.py │ │ └── test.rs │ ├── test.py │ └── test.rs │ └── walk.rs ├── src ├── build_step.rs ├── builder │ ├── commands │ │ ├── alpine.rs │ │ ├── composer.rs │ │ ├── copy.rs │ │ ├── dirs.rs │ │ ├── download.rs │ │ ├── gem.rs │ │ ├── generic.rs │ │ ├── npm.rs │ │ ├── packaging.rs │ │ ├── pip.rs │ │ ├── subcontainer.rs │ │ ├── tarcmd.rs │ │ ├── text.rs │ │ ├── ubuntu.rs │ │ ├── unzip.rs │ │ └── vcs.rs │ ├── context.rs │ ├── distrib.rs │ ├── dns.rs │ ├── error.rs │ ├── guard.rs │ ├── mod.rs │ ├── packages.rs │ └── timer.rs ├── capsule │ ├── build.rs │ ├── download.rs │ ├── mod.rs │ ├── packages.rs │ ├── run.rs │ └── script.rs ├── config │ ├── builders.rs │ ├── command.rs │ ├── config.rs │ ├── containers.rs │ ├── mod.rs │ ├── range.rs │ ├── read_settings.rs │ ├── settings.rs │ ├── validate.rs │ ├── version.rs │ └── volumes.rs ├── container │ ├── mod.rs │ ├── mount.rs │ ├── network.rs │ ├── nsutil.rs │ ├── root.rs │ ├── uidmap.rs │ └── util.rs ├── digest.rs ├── file_util.rs ├── launcher │ ├── build.rs │ ├── capsule.rs │ ├── commands.rs │ ├── completion.rs │ ├── environ.rs │ ├── integration.rs │ ├── list.rs │ ├── mod.rs │ ├── network.rs │ ├── options.rs │ ├── pack.rs │ ├── prerequisites.rs │ ├── push.rs │ ├── simple.rs │ ├── socket.rs │ ├── storage.rs │ ├── storage_dir.rs │ ├── supervisor.rs │ ├── system.rs │ ├── underscore.rs │ ├── user.rs │ ├── volumes.rs │ └── wrap.rs ├── macros.rs ├── main.rs ├── network │ ├── graphs.rs │ ├── iptables.rs │ ├── mod.rs │ └── run.rs ├── options │ ├── build_mode.rs │ ├── compression_type.rs │ ├── mod.rs │ ├── pack.rs │ ├── push.rs │ └── version_hash.rs ├── path_util.rs ├── process_util.rs ├── runner │ └── mod.rs ├── setup_netns │ └── mod.rs ├── storage_dir.rs ├── tty_util.rs ├── version │ ├── error.rs │ ├── mod.rs │ └── version.rs └── wrapper │ ├── build.rs │ ├── capsule.rs │ ├── clean.rs │ ├── commandline.rs │ ├── debug.rs │ ├── hardlink.rs │ ├── init_persistent.rs │ ├── mod.rs │ ├── pack.rs │ ├── run.rs │ ├── setup.rs │ ├── snapshot.rs │ ├── supervise.rs │ └── util.rs ├── tests ├── alpine.bats ├── alpine │ ├── vagga.yaml │ └── vagga_inside_alpine │ │ ├── .gitignore │ │ └── vagga.yaml ├── badcmd.bats ├── badcmd │ └── vagga.yaml ├── capsule.bats ├── capsule │ ├── calc.txt │ ├── script.sh │ └── vagga.yaml ├── completion.bats ├── completion │ └── vagga.yaml ├── composer.bats ├── composer │ ├── Taskfile │ ├── composer.json │ └── vagga.yaml ├── composer_lock │ ├── Taskfile │ ├── composer.json │ ├── composer.lock │ └── vagga.yaml ├── copy.bats ├── copy │ ├── dir │ │ ├── exe.sh │ │ ├── hello │ │ ├── second │ │ └── subdir │ │ │ └── file │ ├── file │ └── vagga.yaml ├── cyclic.bats ├── cyclic │ └── vagga.yaml ├── gem_bundler.bats ├── gem_bundler │ ├── Gemfile │ └── vagga.yaml ├── gem_bundler_lock.bats ├── gem_bundler_lock │ ├── Gemfile │ ├── Gemfile.lock │ └── vagga.yaml ├── generic.bats ├── generic │ ├── .gitignore │ ├── environ.txt │ ├── etc │ │ └── .gitignore │ └── vagga.yaml ├── hardlinking.bats ├── hardlinking │ ├── .gitignore │ ├── project-1 │ │ └── vagga.yaml │ ├── project-2 │ │ └── vagga.yaml │ └── vagga.yaml ├── image.bats ├── image │ └── vagga.yaml ├── inheritance.bats ├── inheritance │ └── vagga.yaml ├── mixins.bats ├── mixins │ ├── mixins1.yaml │ ├── mixins2.yaml │ └── vagga.yaml ├── mixins_version │ ├── mixins.yaml │ └── vagga.yaml ├── network.bats ├── network │ └── vagga.yaml ├── npm.bats ├── npm │ ├── .gitignore │ ├── package.json │ └── vagga.yaml ├── pip.bats ├── pip │ ├── .gitignore │ ├── include-nested.txt │ ├── req-https.txt │ ├── requirements.txt │ └── vagga.yaml ├── prerequisites.bats ├── prerequisites │ └── vagga.yaml ├── readonly.bats ├── subconfig.bats ├── subconfig │ ├── .dockerignore │ ├── Dockerfile │ ├── docker-parser.yaml │ ├── docker2vagga.py │ ├── subdir │ │ ├── docker-subconfigs.yaml │ │ └── vagga.yaml │ └── vagga.yaml ├── tty │ ├── README.rst │ └── vagga.yaml ├── ubuntu.bats ├── ubuntu │ └── vagga.yaml ├── ubuntu_release.bats ├── ubuntu_release │ └── vagga.yaml ├── uidmap.bats ├── uidmap │ └── vagga.yaml ├── vcs.bats ├── vcs │ ├── .gitignore │ └── vagga.yaml ├── version.bats ├── version │ └── vagga.yaml ├── volumes.bats ├── volumes │ └── vagga.yaml ├── yarn.bats └── yarn │ ├── .gitignore │ └── vagga.yaml └── vagga.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | /*.rlib 2 | /*.a 3 | /*.o 4 | *.pyc 5 | .vagga 6 | /tmp 7 | /docs/_build 8 | /dist 9 | 10 | todo.txt 11 | 12 | /vagga 13 | /main 14 | 15 | /apk 16 | /busybox 17 | /alpine-keys.apk 18 | /alpine 19 | 20 | /target 21 | 22 | /tests/image/images 23 | /tests/image/nginx 24 | /tests/inheritance/description-pak 25 | 26 | # directories created by bundler 27 | /tests/gem_bundler/.bundle 28 | /tests/gem_bundler_lock/.bundle 29 | 30 | # emacs files 31 | *~ 32 | \#*# 33 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/.gitmodules -------------------------------------------------------------------------------- /EXIT_CODES.rst: -------------------------------------------------------------------------------- 1 | 2 | vagga_version 3 | ============= 4 | 5 | * 1 -- error when executing command inside container 6 | * 29 -- can't calc hash, need container rebuild 7 | * 121 -- error when launching internal subcommand 8 | * 122 -- can't parse arguments, trying to run vagga as root 9 | * 124 -- error when executing wrapper's subcommand 10 | * 126 -- can't read or parse config, vagga version mismatch, can't stat config directory 11 | * 127 -- unknown command 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Paul Colomiets 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Vagga 3 | ===== 4 | 5 | 6 | Vagga is a fully-userspace container engine inspired by Vagrant_ and Docker_, 7 | specialized for development environments. 8 | 9 | Note version 0.2 changed format of ``vagga.yaml`` see `Release Notes`_ and 10 | Upgrading_ for more info. 11 | 12 | Major Features Are: 13 | 14 | * Running programs in linux containers (not a full virtualization like Vagrant) 15 | * Fully userspace containers, no need for elevated privileges like for Docker_ 16 | * Runs containerized process as a child of current shell, no attach/detach hell 17 | * Images are automatically rebuilt and versioned 18 | * Vagga has tools to manage trees of processes (so you run your 19 | redis-python-nginx server with one command) 20 | * Compatibility with `Vagrant-LXC` and Docker_ 21 | 22 | More deep `feature description in docs `_ 23 | 24 | Disclaimer: This is *beta* quality software. But since it's only used for 25 | development environments it's safe to use for most projects. Some incompatible 26 | changes in configuration file might be introduced until release of vagga 1.0, 27 | but it will never affect your production servers. 28 | 29 | Documentation_ 30 | 31 | .. _vagrant: http://vagrantup.com 32 | .. _docker: http://docker.io 33 | .. _Documentation: http://vagga.readthedocs.org 34 | .. _Vagrant-LXC: https://github.com/fgrehm/vagrant-lxc 35 | .. _Release Notes: http://github.com/tailhook/vagga/blob/master/RELEASE_NOTES.rst 36 | .. _Upgrading: http://vagga.readthedocs.org/en/latest/upgrading.html 37 | 38 | 39 | .. image:: https://badges.gitter.im/Join%20Chat.svg 40 | :alt: Join the chat at https://gitter.im/tailhook/vagga 41 | :target: https://gitter.im/tailhook/vagga?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge 42 | -------------------------------------------------------------------------------- /bulk.yaml: -------------------------------------------------------------------------------- 1 | minimum-bulk: v0.4.1 2 | 3 | metadata: 4 | name: vagga 5 | short-description: A containerisation tool without daemons 6 | long-description: | 7 | A containerization tool specialized in setting up container depdedencies, 8 | running development environments and being first-class CI citizen. 9 | 10 | 11 | versions: 12 | - file: Cargo.toml 13 | block-start: ^\[package\] 14 | block-end: ^\[.*\] 15 | regex: ^version\s*=\s*"(\S+)" 16 | 17 | - file: Cargo.lock 18 | block-start: ^name\s*=\s*"vagga" 19 | block-end: ^\[.*\] 20 | regex: ^version\s*=\s*"(\S+)" 21 | 22 | - file: docs/conf.py 23 | regex: ^version\s*=\s*'(\S+)' 24 | partial-version: ^\d+\.\d+ 25 | 26 | - file: docs/conf.py 27 | regex: ^release\s*=\s*'(\S+)' 28 | 29 | - file: docs/installation.rst 30 | regex: vagga-([\d\.ga-f-]+)\.tar\.xz 31 | 32 | 33 | repositories: 34 | 35 | - kind: debian 36 | suite: static 37 | component: vagga 38 | keep-releases: 1 39 | match-version: ^\d+\.\d+\.\d+$ 40 | add-empty-i386-repo: true 41 | 42 | - kind: debian 43 | suite: static 44 | component: vagga-stable 45 | keep-releases: 1000 46 | match-version: ^\d+\.\d+\.\d+$ 47 | add-empty-i386-repo: true 48 | 49 | - kind: debian 50 | suite: static 51 | component: vagga-testing 52 | keep-releases: 100 53 | add-empty-i386-repo: true 54 | -------------------------------------------------------------------------------- /completions/bash-completion.sh: -------------------------------------------------------------------------------- 1 | _vagga_completion() { 2 | cur="${COMP_WORDS[COMP_CWORD]}" 3 | COMPREPLY=( $(vagga _compgen "${COMP_WORDS[@]:1:$((COMP_CWORD-1))}" -- ${cur} 2>/dev/null) ) 4 | if [[ ${COMPREPLY} == "" ]]; then 5 | COMPREPLY=( $(compgen -f -- ${cur}) ) 6 | fi 7 | return 0 8 | } 9 | 10 | complete -o filenames -F _vagga_completion vagga 11 | -------------------------------------------------------------------------------- /completions/zsh-completion.sh: -------------------------------------------------------------------------------- 1 | #compdef vagga 2 | #autoload 3 | 4 | VAGGA=${VAGGA:-vagga} 5 | 6 | _list () { 7 | local cmds listopts 8 | 9 | # Show hidden options only when underscore is typed 10 | if [[ $words[2] = '_'* ]]; then 11 | listopts="--all" 12 | fi 13 | 14 | # Check if in folder with correct vagga.yaml file 15 | $VAGGA _list 1>/dev/null 2>/dev/null 16 | if [ $? -eq 0 ]; then 17 | IFS=$'\n' cmds=($($VAGGA _list "$1" $listopts)) 18 | else 19 | cmds=() 20 | fi 21 | _describe -t commands 'Available commands' cmds 22 | } 23 | 24 | _arguments -C -s "1: :{_list --zsh}" '*::arg:->args' -- 25 | case $state in 26 | (args) 27 | cmd=${words[1]} 28 | if [[ ${cmd} = "_run" || $cmd = "_build" ]] then; 29 | _arguments -C -s "1: :{_list --containers}" 30 | else 31 | words[1]="$VAGGA _help ${cmd}" 32 | _arguments -C -s -- 33 | fi 34 | esac 35 | -------------------------------------------------------------------------------- /description-pak: -------------------------------------------------------------------------------- 1 | A containerisation tool without daemons 2 | -------------------------------------------------------------------------------- /docs/config.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | Configuration 3 | ============= 4 | 5 | Main vagga configuration file is ``vagga.yaml``. It's usually in the root of 6 | the project dir. 7 | 8 | `Configuration format basics `_. 9 | 10 | .. toctree:: 11 | :maxdepth: 2 12 | 13 | config_overview 14 | container_params 15 | commands 16 | build_commands 17 | build_steps 18 | volumes 19 | upgrading 20 | supervision 21 | pid1mode 22 | capsule_commands 23 | 24 | .. _YAML: http://yaml.org 25 | -------------------------------------------------------------------------------- /docs/double_bridging_vagga_networks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/docs/double_bridging_vagga_networks.png -------------------------------------------------------------------------------- /docs/environment.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: bash 2 | 3 | .. _environment: 4 | 5 | =========== 6 | Environment 7 | =========== 8 | 9 | There are a few ways to pass environment variables from the runner's 10 | environment into a container. 11 | 12 | Firstly, any environment variable that starts with ``VAGGAENV_`` will have it's 13 | prefix stripped, and exposed in the container's environment:: 14 | 15 | $ VAGGAENV_FOO=BAR vagga _run container printenv FOO 16 | BAR 17 | 18 | The ``-e`` or ``--use-env`` command line option can be used to mark environment 19 | variables from the runner's environment that should be passed to container:: 20 | 21 | $ FOO=BAR vagga --use-env=FOO _run container printenv FOO 22 | BAR 23 | 24 | And finally the ``-E``, ``--env`` or ``--environ`` command line option can be 25 | used to assign an environment variable that will be passed to the container:: 26 | 27 | $ vagga --environ FOO=BAR _run container printenv FOO 28 | BAR 29 | 30 | The order of precedence for environment variables from the highest priority to 31 | the lowest: 32 | 33 | #. Options ``-E/--environ`` in the command-line 34 | #. Options ``-e/--use-env`` in the command-line 35 | #. ``VAGGAENV_*`` variables 36 | #. Variables set inside one of the settings files: ``environ`` option 37 | #. Variables set via ``propagate-environ`` setting 38 | #. Variables set in command: ``environ`` option 39 | #. Variables set in container: ``environ`` option 40 | #. Variables set in container: ``environ-file`` option 41 | #. Variables that are auto-propagated: ``*_proxy``, ``TERM`` 42 | -------------------------------------------------------------------------------- /docs/examples/build/gradle.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | Gradle 3 | ====== 4 | 5 | .. literalinclude:: ../../../examples/gradle/vagga.yaml 6 | :language: yaml 7 | -------------------------------------------------------------------------------- /docs/examples/db/clickhouse.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | ClickHouse 3 | =========== 4 | 5 | ClickHouse is an open-source column-oriented database management system (DBMS) for online analytical processing (OLAP). 6 | 7 | `Home `_ / 8 | `Github `_ 9 | 10 | .. literalinclude:: ../../../examples/clickhouse/vagga.yaml 11 | :language: yaml 12 | -------------------------------------------------------------------------------- /docs/examples/db/cockroachdb.rst: -------------------------------------------------------------------------------- 1 | =========== 2 | CockroachDB 3 | =========== 4 | 5 | Here is one example of running single node CockroachDB: 6 | 7 | .. literalinclude:: ../../../examples/cockroachdb/vagga.yaml 8 | :language: yaml 9 | 10 | 11 | .. _cockroachdb: https://www.cockroachlabs.com/ 12 | -------------------------------------------------------------------------------- /docs/examples/db/consul.rst: -------------------------------------------------------------------------------- 1 | ====== 2 | Consul 3 | ====== 4 | 5 | .. literalinclude:: ../../../examples/consul/vagga.yaml 6 | :language: yaml 7 | -------------------------------------------------------------------------------- /docs/examples/db/elastic.rst: -------------------------------------------------------------------------------- 1 | Elasticsearch 2 | ------------- 3 | 4 | The elasticsearch example uses :volume:`Persistent` volume so works only on 5 | development version of vagga: 6 | 7 | .. literalinclude:: ../../../examples/elasticsearch/vagga.yaml 8 | :language: yaml 9 | 10 | -------------------------------------------------------------------------------- /docs/examples/db/influx.rst: -------------------------------------------------------------------------------- 1 | Influx DB 2 | ========= 3 | 4 | Influx db is described as a scalable datastore for metrics, events, and real-time analytics 5 | 6 | `Home `_ / 7 | `Github `_ 8 | 9 | Example config: 10 | 11 | .. literalinclude:: ../../../examples/influxdb/vagga.yaml 12 | :language: yaml 13 | -------------------------------------------------------------------------------- /docs/examples/db/kafka.rst: -------------------------------------------------------------------------------- 1 | ===== 2 | Kafka 3 | ===== 4 | 5 | .. literalinclude:: ../../../examples/kafka/vagga.yaml 6 | :language: yaml 7 | -------------------------------------------------------------------------------- /docs/examples/db/postgres.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | PostgreSQL 3 | ========== 4 | 5 | Here is one example of running posgres. 6 | 7 | .. literalinclude:: ../../../examples/postgres/vagga.yaml 8 | :language: yaml 9 | 10 | There is a more complicated example of `postgres with alembic migrations`__ 11 | 12 | __ https://github.com/tailhook/vagga/tree/master/examples/postgres-alembic 13 | -------------------------------------------------------------------------------- /docs/examples/db/redis.rst: -------------------------------------------------------------------------------- 1 | Redis 2 | ----- 3 | 4 | Simplest container with redis looks like this: 5 | 6 | .. literalinclude:: ../../../examples/redis_alpine/vagga.yaml 7 | :language: yaml 8 | 9 | Here is more comprehensive example of redis installed on ubuntu and has two 10 | instances started in parallel: 11 | 12 | .. literalinclude:: ../../../examples/redis/vagga.yaml 13 | :language: yaml 14 | -------------------------------------------------------------------------------- /docs/examples/db/rethinkdb.rst: -------------------------------------------------------------------------------- 1 | RethinkDB 2 | ========= 3 | 4 | RethinkDB_ is described as: 5 | 6 | RethinkDB is the open-source, scalable database 7 | that makes building realtime apps dramatically easier. 8 | 9 | .. _rethinkdb: https://www.rethinkdb.com/ 10 | 11 | 12 | Because RethinkDB has an Ubuntu package, it's easy to setup: 13 | 14 | .. literalinclude:: ../../../examples/rethinkdb/vagga.yaml 15 | :language: yaml 16 | :lines: 5-21, 28-33 17 | 18 | We also have a configued `example chat`_ application `in the repository`_, 19 | that you may run with alongside with the database itself as follows:: 20 | 21 | vagga example-chat 22 | 23 | .. _example chat: https://github.com/rethinkdb/rethinkdb-example-nodejs-chat 24 | .. _in the repository: https://github.com/tailhook/vagga/tree/master/examples/rethinkdb 25 | -------------------------------------------------------------------------------- /docs/examples/doc/sphinx.rst: -------------------------------------------------------------------------------- 1 | ==================== 2 | Sphinx Documentation 3 | ==================== 4 | 5 | The simplest way to generate sphinx documentation is to use ``py-sphinx`` 6 | package from Alpine linux: 7 | 8 | .. literalinclude:: ../../../examples/sphinx_doc/vagga.yaml 9 | :language: yaml 10 | 11 | To start documentation from scratch (if you had no sphinx docs before), run 12 | the following once (and answer the questions):: 13 | 14 | vagga _run doc sphinx-quickstart ./doc 15 | 16 | And add it to the git repository:: 17 | 18 | echo "/_build" >> doc/.gitignore 19 | git add doc 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /docs/examples/misc/certificate.rst: -------------------------------------------------------------------------------- 1 | Adding a Custom Certificate 2 | =========================== 3 | 4 | This is useful if you have self-signed sertificates that you use on local or 5 | stating or corporate resources. 6 | 7 | In ubuntu it looks like this: 8 | 9 | .. code-block:: yaml 10 | 11 | containers: 12 | some-container: 13 | setup: 14 | - !Ubuntu xenial 15 | - !Install [ca-certificates] 16 | - !Download 17 | url: http://example.com/your_company_root.crt 18 | path: /usr/local/share/ca-certificates/your_company_root.crt 19 | - !Sh update-ca-certificates 20 | 21 | 22 | Important thing here is that ``http://example.com/your_company_root.crt`` 23 | should be either on a HTTP (not encrypted) host or have a certificate signed 24 | by a well-known authority (included in ubuntu ``ca-certificates`` package). 25 | -------------------------------------------------------------------------------- /docs/examples/misc/flaky-network.rst: -------------------------------------------------------------------------------- 1 | ===================================== 2 | Network Tolerance Testing (and Nginx) 3 | ===================================== 4 | 5 | Somewhat tiny example of the network tolerance testing code is contained 6 | in the following example: 7 | 8 | .. literalinclude:: ../../../examples/flaky_network/vagga.yaml 9 | :language: yaml 10 | 11 | 12 | .. _nginx: 13 | 14 | This example also includes almost a smallest possible nginx configuration: 15 | 16 | .. literalinclude:: ../../../examples/flaky_network/nginx.conf 17 | :language: yaml 18 | 19 | 20 | .. note:: 21 | 22 | The nginx spits the following message just after start:: 23 | 24 | nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (30: Read-only file system) 25 | 26 | It's fine, we can't change this directory as it's hardcoded into the 27 | source. While we can mount :volume:`Tmpfs` volume into 28 | ``/var/log/nginx`` we don't have to, as all other messages are actually 29 | logged into the ``stderr`` as configured. So this is just annoying and 30 | useless warning that is safe to ignore. 31 | 32 | -------------------------------------------------------------------------------- /docs/examples/misc/graphite.rst: -------------------------------------------------------------------------------- 1 | ======== 2 | Graphite 3 | ======== 4 | 5 | .. literalinclude:: ../../../examples/graphite/vagga.yaml 6 | :language: yaml 7 | -------------------------------------------------------------------------------- /docs/examples/misc/selenium.rst: -------------------------------------------------------------------------------- 1 | ============== 2 | Selenium Tests 3 | ============== 4 | 5 | Running selenium with vagga is as easy as anything else. 6 | 7 | Setting up the GUI may take some effort because you need a display, but 8 | starting PhantomJS as a driver looks like the following: 9 | 10 | .. literalinclude:: ../../../examples/selenium_pytest/vagga.yaml 11 | :language: yaml 12 | 13 | And the test may look like the following: 14 | 15 | .. literalinclude:: ../../../examples/selenium_pytest/test.py 16 | :language: python3 17 | 18 | To run the test just type:: 19 | 20 | > vagga test 21 | 22 | -------------------------------------------------------------------------------- /docs/examples/misc/travis.rst: -------------------------------------------------------------------------------- 1 | ========== 2 | Travis Gem 3 | ========== 4 | 5 | The following snippet installs travis gem (into container). For example to 6 | provide github token to `Travis CI`_ (so that it can push to github), you 7 | can run the following:: 8 | 9 | $ vagga travis encrypt --repo xxx/yyy --org GH_TOKEN=zzz 10 | 11 | The vagga configuration for the command: 12 | 13 | .. literalinclude:: ../../../examples/travis_gem/vagga.yaml 14 | :language: yaml 15 | 16 | 17 | .. _Travis CI: http://travis-ci.org 18 | -------------------------------------------------------------------------------- /docs/examples/tutorials/django.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../../examples/tutorials/django/README.rst 2 | -------------------------------------------------------------------------------- /docs/examples/tutorials/golang_minimal.rst: -------------------------------------------------------------------------------- 1 | Minimal Container With Go Application 2 | ===================================== 3 | 4 | 5 | We have 6 | -------------------------------------------------------------------------------- /docs/examples/tutorials/laravel.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../../examples/tutorials/laravel/README.rst 2 | -------------------------------------------------------------------------------- /docs/examples/tutorials/rails.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../../../examples/tutorials/ruby_on_rails/README.rst 2 | -------------------------------------------------------------------------------- /docs/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/docs/favicon.png -------------------------------------------------------------------------------- /docs/info.rst: -------------------------------------------------------------------------------- 1 | About Vagga 2 | =========== 3 | 4 | Contents: 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | what_is_vagga 10 | vagga_features 11 | compare_to_docker 12 | compare_to_vagrant 13 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinxcontrib-domaintools==0.1 2 | sphinx_rtd_theme 3 | -------------------------------------------------------------------------------- /docs/running.rst: -------------------------------------------------------------------------------- 1 | .. highlight:: bash 2 | 3 | ======= 4 | Running 5 | ======= 6 | 7 | 8 | Usually running vagga is as simple as:: 9 | 10 | $ vagga run 11 | 12 | To find out commands you may run bare ``vagga``:: 13 | 14 | $ vagga 15 | Available commands: 16 | run Run mysample project 17 | build-docs Build documentation using sphinx 18 | 19 | .. toctree:: 20 | :maxdepth: 2 21 | 22 | commandline 23 | environment 24 | settings 25 | gitlab 26 | errors 27 | system_settings 28 | overlayfs 29 | -------------------------------------------------------------------------------- /docs/sidebar-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/docs/sidebar-logo.png -------------------------------------------------------------------------------- /docs/test.rst: -------------------------------------------------------------------------------- 1 | 2 | Vagga Commands 3 | ============== 4 | 5 | 6 | build-packages 7 | -------------- 8 | 9 | :Container: rust-musl 10 | 11 | Create an ubuntu (.deb) package using checkinstall in container and tar.gz. Both put into `dist/` 12 | 13 | 14 | build-packages-testing 15 | ---------------------- 16 | 17 | :Container: rust-musl 18 | 19 | Same as build-packages but with debugging info enabled 20 | 21 | 22 | cargo 23 | ----- 24 | 25 | :Container: rust-musl 26 | 27 | Run arbitrary cargo command 28 | 29 | 30 | doc 31 | --- 32 | 33 | :Container: docs 34 | 35 | Build vagga documentation 36 | 37 | 38 | make 39 | ---- 40 | 41 | :Container: rust-musl 42 | 43 | Build vagga 44 | 45 | 46 | make-release 47 | ------------ 48 | 49 | :Container: rust-musl 50 | 51 | Build vagga with optimizations 52 | 53 | 54 | print-env 55 | --------- 56 | 57 | :Container: docs 58 | 59 | no description 60 | 61 | 62 | test 63 | ---- 64 | 65 | :Container: test 66 | 67 | Run self tests 68 | 69 | 70 | test-internal 71 | ------------- 72 | 73 | :Container: rust-musl 74 | 75 | Run rust tests of vagga 76 | 77 | -------------------------------------------------------------------------------- /docs/vaggadomain.py: -------------------------------------------------------------------------------- 1 | from sphinxcontrib.domaintools import custom_domain 2 | 3 | 4 | def setup(app): 5 | app.add_domain(custom_domain('VaggaConfig', 6 | name = 'vagga', 7 | label = "Vagga Config", 8 | 9 | elements = dict( 10 | opt = dict( 11 | objname = "Yaml Option", 12 | indextemplate = "pair: %s; Option", 13 | ), 14 | cmd = dict( 15 | objname = "Vagga Command", 16 | indextemplate = "pair: %s; Command", 17 | ), 18 | volume = dict( 19 | objname = "Volume Type", 20 | indextemplate = "pair: %s; Volume Type", 21 | ), 22 | step = dict( 23 | objname = "Build Step", 24 | indextemplate = "pair: %s; Build Step", 25 | ), 26 | ))) 27 | -------------------------------------------------------------------------------- /examples/clickhouse/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | ubuntu: 3 | setup: 4 | - !Ubuntu xenial 5 | - !AptTrust keys: [E0C56BD4] 6 | - !UbuntuRepo 7 | url: https://repo.yandex.ru/clickhouse/xenial 8 | suite: stable 9 | components: [main] 10 | - !Install [tzdata, clickhouse-server-common, clickhouse-client] 11 | - !EnsureDir /var/lib/clickhouse 12 | volumes: 13 | /var/lib/clickhouse: !Persistent 14 | name: clickhouse-data 15 | 16 | commands: 17 | server: &server !Command 18 | description: Run clickhouse server 19 | container: ubuntu 20 | work-dir: /etc/clickhouse-server 21 | run: clickhouse server 22 | 23 | client: &client !Command 24 | description: Run clickhouse client 25 | container: ubuntu 26 | run: sleep 3 && clickhouse-client 27 | 28 | run: !Supervise 29 | description: Run clickhouse server and client 30 | children: 31 | server: *server 32 | client: *client 33 | -------------------------------------------------------------------------------- /examples/cockroachdb/vagga.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Sample Vagga configuration for running CockroachDB server 3 | # 4 | 5 | containers: 6 | ubuntu: 7 | setup: 8 | - !Ubuntu xenial 9 | - !Tar 10 | url: https://binaries.cockroachdb.com/cockroach-v1.0.4.linux-amd64.tgz 11 | subdir: cockroach-v1.0.4.linux-amd64 12 | path: /usr/bin 13 | - !EnsureDir /data 14 | volumes: 15 | /data: !Persistent 16 | name: cockroach 17 | 18 | commands: 19 | 20 | server: &server !Command 21 | description: Run cockroach database 22 | container: ubuntu 23 | run: [cockroach, start, --insecure, --store=path=/data] 24 | 25 | 26 | client: &client !Command 27 | description: Run cockroach shell 28 | container: ubuntu 29 | accepts-arguments: true 30 | run: | 31 | sleep 1 32 | exec cockroach sql --insecure "$@" 33 | 34 | run: !Supervise 35 | description: Run both cockroach server and shell 36 | children: 37 | server: *server 38 | client: *client 39 | -------------------------------------------------------------------------------- /examples/consul/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | ubuntu-consul: 4 | setup: 5 | - !Ubuntu xenial 6 | - !Install [unzip, wget, ca-certificates] 7 | - !Sh | 8 | cd /tmp 9 | wget https://releases.hashicorp.com/consul/0.6.4/consul_0.6.4_linux_amd64.zip 10 | unzip consul_0.6.4_linux_amd64.zip 11 | cp consul /usr/bin/consul 12 | 13 | commands: 14 | 15 | consul-server: !Command 16 | description: Start consul in server mode 17 | container: ubuntu-consul 18 | run: | 19 | /usr/bin/consul agent -server -bootstrap-expect=1 \ 20 | -data-dir=/tmp/consul -log-level=debug \ 21 | -advertise=127.0.0.1 22 | -------------------------------------------------------------------------------- /examples/elasticsearch/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | elastic: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | # elastic PGP & Repo 7 | - !AptTrust 8 | server: pgp.mit.edu 9 | keys: [D88E42B4] 10 | - !UbuntuRepo 11 | url: http://packages.elastic.co/elasticsearch/2.x/debian 12 | suite: stable 13 | components: [main] 14 | - !Install 15 | - ca-certificates 16 | - ca-certificates-java 17 | - openjdk-8-jre-headless 18 | - elasticsearch=2.3.3 19 | - !EnsureDir /var/elastic 20 | volumes: 21 | /var/elastic: !Persistent { name: elastic } 22 | 23 | commands: 24 | elastic: !Command 25 | description: Run elasticsearch 26 | container: elastic 27 | user-id: 1 28 | external-user-id: 0 29 | run: 30 | - /usr/share/elasticsearch/bin/elasticsearch 31 | - -Des.path.conf=/etc/elasticsearch 32 | - -Des.path.logs=/tmp 33 | - -Des.path.work=/tmp 34 | - -Des.path.data=/var/elastic/data 35 | -------------------------------------------------------------------------------- /examples/firefox/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | browser: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !Install [firefox] 7 | volumes: 8 | /tmp: !Tmpfs 9 | size: 100Mi 10 | mode: 0o1777 11 | subdirs: 12 | .X11-unix: 13 | /tmp/.X11-unix: !BindRW /volumes/X11 14 | 15 | commands: 16 | firefox: !Command 17 | container: browser 18 | environ: { HOME: /tmp } 19 | run: [firefox, --no-remote] 20 | -------------------------------------------------------------------------------- /examples/firefox/vagga_webgl_intel.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | browser: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !Install [chromium-browser, 7 | firefox, icedtea-plugin, 8 | xserver-xorg-video-intel, mesa-utils, libgl1-mesa-dri] 9 | volumes: 10 | /tmp: !Tmpfs 11 | size: 100Mi 12 | mode: 0o1777 13 | subdirs: 14 | .X11-unix: 15 | /tmp/.X11-unix: !BindRW /volumes/X11 16 | 17 | commands: 18 | firefox: !Command 19 | container: browser 20 | environ: { HOME: /tmp } 21 | run: [firefox, --no-remote] 22 | -------------------------------------------------------------------------------- /examples/firefox/vagga_webgl_nvidia.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | browser: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !Install [binutils, pkg-config, mesa-utils] 7 | - !Sh sh /work/NVIDIA-Linux-x86_64-331.67.run -a -N --ui=none --no-kernel-module 8 | - !Sh nvidia-xconfig -a --use-display-device=None --enable-all-gpus --virtual=1280x1024 9 | - !Install [firefox] 10 | volumes: 11 | /tmp: !Tmpfs 12 | size: 100Mi 13 | mode: 0o1777 14 | subdirs: 15 | .X11-unix: 16 | /tmp/.X11-unix: !BindRW /volumes/X11 17 | 18 | commands: 19 | firefox: !Command 20 | container: browser 21 | environ: { HOME: /tmp } 22 | run: [firefox, --no-remote] 23 | -------------------------------------------------------------------------------- /examples/firefox_with_java/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | browser: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !Install [firefox, icedtea-plugin] 7 | # Java can't see HOME environment variable, so we create a special user 8 | - !Sh "useradd myself --home-dir /home/myself --gid 100 -M --uid 1000" 9 | - !EnsureDir /home/myself 10 | volumes: 11 | /home/myself: !Persistent home 12 | /tmp: !Tmpfs 13 | size: 100Mi 14 | mode: 0o1777 15 | subdirs: 16 | .X11-unix: 17 | /tmp/.X11-unix: !BindRW /volumes/X11 18 | environ: 19 | DISPLAY: ":0" 20 | XDG_RUNTIME_DIR: /tmp 21 | 22 | commands: 23 | 24 | firefox: !Command 25 | container: browser 26 | external-user-id: 0 27 | user-id: 1000 28 | run: [firefox, --no-remote] 29 | 30 | # We need to create a mountpoint with a separate command 31 | # so mount a volume just here 32 | prerequisites: [_touch-file] 33 | volumes: 34 | /home/myself/.Xauthority: !BindRO /volumes/x-authority 35 | 36 | # This is needed to create a mountpoint 37 | _touch-file: !Command 38 | container: browser 39 | run: [touch, /home/myself/.Xauthority] 40 | -------------------------------------------------------------------------------- /examples/flaky_network/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | @app.route('/') 6 | def hello_world(): 7 | return "Hello World!" 8 | 9 | if __name__ == '__main__': 10 | app.run(host='0.0.0.0') 11 | -------------------------------------------------------------------------------- /examples/flaky_network/nginx.conf: -------------------------------------------------------------------------------- 1 | daemon off; 2 | master_process off; 3 | worker_processes 1; 4 | user root; 5 | 6 | error_log stderr; 7 | #pid /tmp/nginx.pid; 8 | 9 | events { 10 | worker_connections 1024; 11 | } 12 | 13 | 14 | http { 15 | include /etc/nginx/mime.types; 16 | default_type application/octet-stream; 17 | access_log off; 18 | 19 | client_body_temp_path /tmp 1 2; 20 | proxy_temp_path /tmp 1 2; 21 | fastcgi_temp_path /tmp 1 2; 22 | uwsgi_temp_path /tmp 1 2; 23 | scgi_temp_path /tmp 1 2; 24 | 25 | sendfile on; 26 | 27 | keepalive_timeout 65; 28 | 29 | server { 30 | listen 8000; 31 | large_client_header_buffers 4 64k; 32 | 33 | charset utf-8; 34 | 35 | location / { 36 | proxy_pass http://172.18.0.2:5000; 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /examples/influxdb/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | influxdb: 3 | setup: 4 | - !Ubuntu xenial 5 | - !Download 6 | url: https://dl.influxdata.com/influxdb/releases/influxdb_0.13.0_amd64.deb 7 | path: /tmp/influxdb.deb 8 | - !Sh dpkg -i /tmp/influxdb.deb && rm /tmp/influxdb.deb 9 | - !EnsureDir /var/lib/influxdb 10 | volumes: 11 | /var/lib/influxdb: !Persistent { name: influxdb } 12 | 13 | commands: 14 | influx: !Command 15 | description: Run influxdb 16 | container: influxdb 17 | user-id: 1 18 | external-user-id: 0 19 | run: 20 | - influxd 21 | -------------------------------------------------------------------------------- /examples/openldap-slapd/init.ldif: -------------------------------------------------------------------------------- 1 | dn: dc=ldap,dc=example,dc=org 2 | objectClass: top 3 | objectClass: dcObject 4 | objectClass: organization 5 | o: example 6 | dc: ldap 7 | -------------------------------------------------------------------------------- /examples/openldap-slapd/newuser.ldif: -------------------------------------------------------------------------------- 1 | dn: uid=newuser,dc=ldap,dc=example,dc=org 2 | objectClass: top 3 | objectClass: person 4 | objectClass: organizationalPerson 5 | objectClass: inetOrgPerson 6 | objectClass: posixAccount 7 | objectClass: shadowAccount 8 | uid: newuser 9 | cn: newuser 10 | sn: Doe 11 | loginShell: /bin/bash 12 | uidNumber: 88888 13 | gidNumber: 88888 14 | homeDirectory: /home/newuser/ 15 | userPassword: {SSHA}9jA01JlieepnbrBgbz9pXK+4u6+mRwby 16 | -------------------------------------------------------------------------------- /examples/postgres-alembic/alembic.ini: -------------------------------------------------------------------------------- 1 | [alembic] 2 | script_location = alembic 3 | # sqlalchemy.url is set in env.py from environment variable 4 | 5 | 6 | # Logging configuration 7 | [loggers] 8 | keys = root,sqlalchemy,alembic 9 | 10 | [handlers] 11 | keys = console 12 | 13 | [formatters] 14 | keys = generic 15 | 16 | [logger_root] 17 | level = WARN 18 | handlers = console 19 | qualname = 20 | 21 | [logger_sqlalchemy] 22 | level = WARN 23 | handlers = 24 | qualname = sqlalchemy.engine 25 | 26 | [logger_alembic] 27 | level = INFO 28 | handlers = 29 | qualname = alembic 30 | 31 | [handler_console] 32 | class = StreamHandler 33 | args = (sys.stderr,) 34 | level = NOTSET 35 | formatter = generic 36 | 37 | [formatter_generic] 38 | format = %(levelname)-5.5s [%(name)s] %(message)s 39 | datefmt = %H:%M:%S 40 | -------------------------------------------------------------------------------- /examples/postgres-alembic/alembic/env.py: -------------------------------------------------------------------------------- 1 | from __future__ import with_statement 2 | import os 3 | from alembic import context 4 | from sqlalchemy import engine_from_config, pool 5 | from logging.config import fileConfig 6 | 7 | config = context.config 8 | fileConfig(config.config_file_name) 9 | target_metadata = None 10 | 11 | config.set_main_option('sqlalchemy.url', os.environ.get('DATABASE_URL')) 12 | 13 | 14 | def run_migrations_offline(): 15 | """Run migrations in 'offline' mode. 16 | 17 | This configures the context with just a URL 18 | and not an Engine, though an Engine is acceptable 19 | here as well. By skipping the Engine creation 20 | we don't even need a DBAPI to be available. 21 | 22 | Calls to context.execute() here emit the given string to the 23 | script output. 24 | 25 | """ 26 | url = config.get_main_option("sqlalchemy.url") 27 | context.configure( 28 | url=url, target_metadata=target_metadata, literal_binds=True) 29 | 30 | with context.begin_transaction(): 31 | context.run_migrations() 32 | 33 | 34 | def run_migrations_online(): 35 | """Run migrations in 'online' mode. 36 | 37 | In this scenario we need to create an Engine 38 | and associate a connection with the context. 39 | 40 | """ 41 | connectable = engine_from_config( 42 | config.get_section(config.config_ini_section), 43 | prefix='sqlalchemy.', 44 | poolclass=pool.NullPool) 45 | 46 | with connectable.connect() as connection: 47 | context.configure( 48 | connection=connection, 49 | target_metadata=target_metadata 50 | ) 51 | 52 | with context.begin_transaction(): 53 | context.run_migrations() 54 | 55 | if context.is_offline_mode(): 56 | run_migrations_offline() 57 | else: 58 | run_migrations_online() 59 | -------------------------------------------------------------------------------- /examples/postgres-alembic/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = ${repr(up_revision)} 11 | down_revision = ${repr(down_revision)} 12 | branch_labels = ${repr(branch_labels)} 13 | depends_on = ${repr(depends_on)} 14 | 15 | from alembic import op 16 | import sqlalchemy as sa 17 | ${imports if imports else ""} 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /examples/postgres-alembic/alembic/versions/360aff35f0d_init.py: -------------------------------------------------------------------------------- 1 | """init 2 | 3 | Revision ID: 360aff35f0d 4 | Revises: 5 | Create Date: 2015-10-30 15:24:23.181676 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = '360aff35f0d' 11 | down_revision = None 12 | branch_labels = None 13 | depends_on = None 14 | 15 | from alembic import op 16 | import sqlalchemy as sa 17 | 18 | 19 | def upgrade(): 20 | op.create_table('tbl', 21 | sa.Column('id', sa.Integer(), nullable=False), 22 | sa.Column('name', sa.String(length=256), nullable=False), 23 | sa.PrimaryKeyConstraint('id') 24 | ) 25 | 26 | 27 | def downgrade(): 28 | op.drop_table('tbl') 29 | -------------------------------------------------------------------------------- /examples/postgres-alembic/app.py: -------------------------------------------------------------------------------- 1 | import os 2 | from flask import Flask 3 | from flask.ext.sqlalchemy import SQLAlchemy 4 | 5 | app = Flask(__name__) 6 | app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL') 7 | db = SQLAlchemy(app) 8 | 9 | @app.route('/') 10 | def hello_world(): 11 | return '; '.join(db.engine.table_names()) 12 | 13 | if __name__ == '__main__': 14 | app.run(host='0.0.0.0') 15 | -------------------------------------------------------------------------------- /examples/redis_alpine/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | redis: 3 | setup: 4 | - !Alpine v3.5 5 | - !Install [redis] 6 | 7 | commands: 8 | 9 | server: !Command 10 | container: redis 11 | run: "redis-server --daemonize no" 12 | 13 | cli: !Command 14 | container: redis 15 | run: [redis-cli] 16 | -------------------------------------------------------------------------------- /examples/rethinkdb/vagga.yaml: -------------------------------------------------------------------------------- 1 | # 2 | # Sample Vagga configuration for running RethinkDB server 3 | # 4 | 5 | containers: 6 | ubuntu: 7 | setup: 8 | - !Ubuntu xenial 9 | - !UbuntuRepo 10 | url: http://download.rethinkdb.com/apt 11 | suite: xenial 12 | components: [main] 13 | - !Download 14 | url: https://download.rethinkdb.com/apt/pubkey.gpg 15 | path: /tmp/pubkey.gpg 16 | - !Sh apt-key add /tmp/pubkey.gpg 17 | - !Install [rethinkdb] 18 | - !EnsureDir /data 19 | volumes: 20 | /data: !Persistent data 21 | 22 | example-chat: 23 | setup: 24 | - !Alpine v3.5 25 | - !Install 26 | - python # for node-gyp 27 | - netcat-openbsd # to check when rethinkdb is ready 28 | - !NpmInstall [https://github.com/rethinkdb/rethinkdb-example-nodejs-chat.git] 29 | 30 | commands: 31 | 32 | rethink: &rethink !Command 33 | description: Run rethink database 34 | container: ubuntu 35 | run: [rethinkdb, --directory, /data] 36 | 37 | example-chat: !Supervise 38 | description: Run both rethink and example-chat 39 | children: 40 | rethink: *rethink 41 | chat: !Command 42 | container: example-chat 43 | work-dir: /usr/lib/node_modules/awesome_chat2k/ 44 | run: | 45 | while ! nc -z 127.0.0.1 28015; do 46 | sleep 1 47 | done 48 | node app 49 | -------------------------------------------------------------------------------- /examples/selenium_pytest/test.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | from selenium.webdriver.common.keys import Keys 3 | 4 | 5 | def test_example(): 6 | driver = webdriver.PhantomJS() 7 | driver.get("http://vagga.readthedocs.org/") 8 | assert "Welcome to Vagga" in driver.title 9 | driver.close() 10 | 11 | 12 | if __name__ == '__main__': 13 | test_example() 14 | -------------------------------------------------------------------------------- /examples/selenium_pytest/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | selenium: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !Install [libfontconfig1] 7 | - !Py3Install [selenium, py, pytest] 8 | # The phantomjs from Ubuntu repository seems to have problems with headless 9 | # environments, so we fetch the binary providd by the developers 10 | - !TarInstall 11 | url: https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 12 | script: cp bin/phantomjs /usr/local/bin/phantomjs 13 | 14 | commands: 15 | test: !Command 16 | description: Run selenium test 17 | container: selenium 18 | run: [py.test, test.py] 19 | -------------------------------------------------------------------------------- /examples/sphinx_doc/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | doc: 4 | setup: 5 | - !Alpine v3.6 6 | - !Install [alpine-base, py-sphinx, make] 7 | # If you require additional packages to build docs uncomment this 8 | # - !Py3Requirements doc/requirements.txt 9 | 10 | commands: 11 | 12 | doc: !Command 13 | description: Build documentation 14 | container: doc 15 | run: [make, html] 16 | work-dir: doc 17 | epilog: | 18 | -------------------------------------------------------- 19 | Documentation is built under doc/_build/html/index.html 20 | -------------------------------------------------------------------------------- /examples/travis_gem/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | travis: 3 | setup: 4 | - !Ubuntu xenial 5 | - !UbuntuUniverse 6 | - !BuildDeps [autoconf, automake, autotools-dev, autogen, libtool, libltdl-dev] 7 | - !GemInstall [travis] 8 | 9 | commands: 10 | 11 | travis: !Command 12 | container: travis 13 | run: [travis] 14 | environ: { HOME: /tmp } 15 | -------------------------------------------------------------------------------- /examples/tutorials/django/.gitignore: -------------------------------------------------------------------------------- 1 | db.sqlite3 2 | -------------------------------------------------------------------------------- /examples/tutorials/django/MyProject/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/django/MyProject/__init__.py -------------------------------------------------------------------------------- /examples/tutorials/django/MyProject/urls.py: -------------------------------------------------------------------------------- 1 | """MyProject URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/1.9/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.conf.urls import url, include 14 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 15 | """ 16 | from django.conf.urls import url, include 17 | from django.contrib import admin 18 | 19 | urlpatterns = [ 20 | url(r'^', include('blog.urls', namespace='blog')), 21 | url(r'^admin/', admin.site.urls), 22 | ] 23 | -------------------------------------------------------------------------------- /examples/tutorials/django/MyProject/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for MyProject project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyProject.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/django/blog/__init__.py -------------------------------------------------------------------------------- /examples/tutorials/django/blog/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | from .models import Article 3 | 4 | 5 | @admin.register(Article) 6 | class ArticleAdmin(admin.ModelAdmin): 7 | list_display = ('title',) 8 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class BlogConfig(AppConfig): 5 | name = 'blog' 6 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.9.2 on 2016-02-18 11:57 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='Article', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('title', models.CharField(max_length=100)), 21 | ('body', models.TextField()), 22 | ], 23 | ), 24 | ] 25 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/django/blog/migrations/__init__.py -------------------------------------------------------------------------------- /examples/tutorials/django/blog/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | 4 | class Article(models.Model): 5 | title = models.CharField(max_length=100) 6 | body = models.TextField() 7 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/templates/blog/article_detail.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Article List 5 | 6 | 7 |

{{ article.title }}

8 |

9 | {{ article.body }} 10 |

11 | 12 | 13 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/templates/blog/article_list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Article List 5 | 6 | 7 |

Article List

8 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/urls.py: -------------------------------------------------------------------------------- 1 | from django.conf.urls import url 2 | from django.views.decorators.cache import cache_page 3 | from . import views 4 | 5 | cache_15m = cache_page(60 * 15) 6 | 7 | urlpatterns = [ 8 | url(r'^$', views.ArticleList.as_view(), name='article_list'), 9 | url(r'^(?P\d+?)$', cache_15m(views.ArticleDetail.as_view()), name='article_detail'), 10 | ] 11 | -------------------------------------------------------------------------------- /examples/tutorials/django/blog/views.py: -------------------------------------------------------------------------------- 1 | from django.views import generic 2 | from .models import Article 3 | 4 | 5 | class ArticleList(generic.ListView): 6 | model = Article 7 | paginate_by = 10 8 | 9 | 10 | class ArticleDetail(generic.DetailView): 11 | model = Article 12 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/django/common/__init__.py -------------------------------------------------------------------------------- /examples/tutorials/django/common/admin.py: -------------------------------------------------------------------------------- 1 | from django.contrib import admin 2 | 3 | # Register your models here. 4 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class CommonConfig(AppConfig): 5 | name = 'common' 6 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/migrations/0001_create_superuser.py: -------------------------------------------------------------------------------- 1 | from django.db import migrations 2 | from django.contrib.auth.hashers import make_password 3 | 4 | 5 | def create_admin_user(apps, schema_editor): 6 | User = apps.get_model("auth", "User") 7 | User.objects.create(username='admin', 8 | email='admin@example.com', 9 | password=make_password('change_me'), 10 | is_superuser=True, 11 | is_staff=True, 12 | is_active=True) 13 | 14 | 15 | class Migration(migrations.Migration): 16 | 17 | dependencies = [ 18 | ('auth', '__latest__') 19 | ] 20 | 21 | operations = [ 22 | migrations.RunPython(create_admin_user) 23 | ] 24 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/django/common/migrations/__init__.py -------------------------------------------------------------------------------- /examples/tutorials/django/common/models.py: -------------------------------------------------------------------------------- 1 | from django.db import models 2 | 3 | # Create your models here. 4 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/tests.py: -------------------------------------------------------------------------------- 1 | from django.test import TestCase 2 | 3 | # Create your tests here. 4 | -------------------------------------------------------------------------------- /examples/tutorials/django/common/views.py: -------------------------------------------------------------------------------- 1 | from django.shortcuts import render 2 | 3 | # Create your views here. 4 | -------------------------------------------------------------------------------- /examples/tutorials/django/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyProject.settings") 7 | 8 | from django.core.management import execute_from_command_line 9 | 10 | execute_from_command_line(sys.argv) 11 | -------------------------------------------------------------------------------- /examples/tutorials/django/requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.10.5 2 | django-environ==0.4.1 3 | psycopg2==2.6.2 4 | pylibmc==1.5.1 5 | six==1.10.0 6 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/.env.example: -------------------------------------------------------------------------------- 1 | APP_ENV=local 2 | APP_KEY= 3 | APP_DEBUG=true 4 | APP_LOG_LEVEL=debug 5 | APP_URL=http://localhost 6 | 7 | DB_CONNECTION=mysql 8 | DB_HOST=127.0.0.1 9 | DB_PORT=3306 10 | DB_DATABASE=homestead 11 | DB_USERNAME=homestead 12 | DB_PASSWORD=secret 13 | 14 | BROADCAST_DRIVER=log 15 | CACHE_DRIVER=file 16 | SESSION_DRIVER=file 17 | QUEUE_DRIVER=sync 18 | 19 | REDIS_HOST=127.0.0.1 20 | REDIS_PASSWORD=null 21 | REDIS_PORT=6379 22 | 23 | MAIL_DRIVER=smtp 24 | MAIL_HOST=mailtrap.io 25 | MAIL_PORT=2525 26 | MAIL_USERNAME=null 27 | MAIL_PASSWORD=null 28 | MAIL_ENCRYPTION=null 29 | 30 | PUSHER_APP_ID= 31 | PUSHER_APP_KEY= 32 | PUSHER_APP_SECRET= 33 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/storage 3 | /public/hot 4 | /storage/*.key 5 | /vendor 6 | /.idea 7 | Homestead.json 8 | Homestead.yaml 9 | .env 10 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Article.php: -------------------------------------------------------------------------------- 1 | command('inspire') 28 | // ->hourly(); 29 | } 30 | 31 | /** 32 | * Register the Closure based commands for the application. 33 | * 34 | * @return void 35 | */ 36 | protected function commands() 37 | { 38 | require base_path('routes/console.php'); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Controllers/Auth/ForgotPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Controllers/Auth/LoginController.php: -------------------------------------------------------------------------------- 1 | middleware('guest', ['except' => 'logout']); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Controllers/Auth/ResetPasswordController.php: -------------------------------------------------------------------------------- 1 | middleware('guest'); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | middleware('auth'); 17 | } 18 | 19 | /** 20 | * Show the application dashboard. 21 | * 22 | * @return \Illuminate\Http\Response 23 | */ 24 | public function index() 25 | { 26 | return view('home'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | check()) { 21 | return redirect('/home'); 22 | } 23 | 24 | return $next($request); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 'App\Policies\ModelPolicy', 17 | ]; 18 | 19 | /** 20 | * Register any authentication / authorization services. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | $this->registerPolicies(); 27 | 28 | // 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | [ 17 | 'App\Listeners\EventListener', 18 | ], 19 | ]; 20 | 21 | /** 22 | * Register any events for your application. 23 | * 24 | * @return void 25 | */ 26 | public function boot() 27 | { 28 | parent::boot(); 29 | 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/app/User.php: -------------------------------------------------------------------------------- 1 | =5.6.4", 9 | "laravel/framework": "5.4.*", 10 | "laravel/tinker": "~1.0", 11 | "predis/predis": "^1.1" 12 | }, 13 | "require-dev": { 14 | "fzaninotto/faker": "~1.4", 15 | "mockery/mockery": "0.9.*", 16 | "phpunit/phpunit": "~5.7" 17 | }, 18 | "autoload": { 19 | "classmap": [ 20 | "database" 21 | ], 22 | "psr-4": { 23 | "App\\": "app/" 24 | } 25 | }, 26 | "autoload-dev": { 27 | "psr-4": { 28 | "Tests\\": "tests/" 29 | } 30 | }, 31 | "scripts": { 32 | "post-root-package-install": [ 33 | "php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 34 | ], 35 | "post-create-project-cmd": [ 36 | "php artisan key:generate" 37 | ], 38 | "post-install-cmd": [ 39 | "Illuminate\\Foundation\\ComposerScripts::postInstall", 40 | "php artisan optimize" 41 | ], 42 | "post-update-cmd": [ 43 | "Illuminate\\Foundation\\ComposerScripts::postUpdate", 44 | "php artisan optimize" 45 | ] 46 | }, 47 | "config": { 48 | "preferred-install": "dist", 49 | "sort-packages": true 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/config/broadcasting.php: -------------------------------------------------------------------------------- 1 | env('BROADCAST_DRIVER', 'null'), 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Broadcast Connections 23 | |-------------------------------------------------------------------------- 24 | | 25 | | Here you may define all of the broadcast connections that will be used 26 | | to broadcast events to other systems or over websockets. Samples of 27 | | each available type of connection are provided inside this array. 28 | | 29 | */ 30 | 31 | 'connections' => [ 32 | 33 | 'pusher' => [ 34 | 'driver' => 'pusher', 35 | 'key' => env('PUSHER_APP_KEY'), 36 | 'secret' => env('PUSHER_APP_SECRET'), 37 | 'app_id' => env('PUSHER_APP_ID'), 38 | 'options' => [ 39 | // 40 | ], 41 | ], 42 | 43 | 'redis' => [ 44 | 'driver' => 'redis', 45 | 'connection' => 'default', 46 | ], 47 | 48 | 'log' => [ 49 | 'driver' => 'log', 50 | ], 51 | 52 | 'null' => [ 53 | 'driver' => 'null', 54 | ], 55 | 56 | ], 57 | 58 | ]; 59 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/config/services.php: -------------------------------------------------------------------------------- 1 | [ 18 | 'domain' => env('MAILGUN_DOMAIN'), 19 | 'secret' => env('MAILGUN_SECRET'), 20 | ], 21 | 22 | 'ses' => [ 23 | 'key' => env('SES_KEY'), 24 | 'secret' => env('SES_SECRET'), 25 | 'region' => 'us-east-1', 26 | ], 27 | 28 | 'sparkpost' => [ 29 | 'secret' => env('SPARKPOST_SECRET'), 30 | ], 31 | 32 | 'stripe' => [ 33 | 'model' => App\User::class, 34 | 'key' => env('STRIPE_KEY'), 35 | 'secret' => env('STRIPE_SECRET'), 36 | ], 37 | 38 | ]; 39 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/config/view.php: -------------------------------------------------------------------------------- 1 | [ 17 | realpath(base_path('resources/views')), 18 | ], 19 | 20 | /* 21 | |-------------------------------------------------------------------------- 22 | | Compiled View Path 23 | |-------------------------------------------------------------------------- 24 | | 25 | | This option determines where all the compiled Blade templates will be 26 | | stored for your application. Typically, this is within the storage 27 | | directory. However, as usual, you are free to change this value. 28 | | 29 | */ 30 | 31 | 'compiled' => realpath(storage_path('framework/views')), 32 | 33 | ]; 34 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite 2 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/factories/ModelFactory.php: -------------------------------------------------------------------------------- 1 | define(App\User::class, function (Faker\Generator $faker) { 16 | static $password; 17 | 18 | return [ 19 | 'name' => $faker->name, 20 | 'email' => $faker->unique()->safeEmail, 21 | 'password' => $password ?: $password = bcrypt('secret'), 22 | 'remember_token' => str_random(10), 23 | ]; 24 | }); 25 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/migrations/2014_10_12_000000_create_users_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name'); 19 | $table->string('email')->unique(); 20 | $table->string('password'); 21 | $table->rememberToken(); 22 | $table->timestamps(); 23 | }); 24 | } 25 | 26 | /** 27 | * Reverse the migrations. 28 | * 29 | * @return void 30 | */ 31 | public function down() 32 | { 33 | Schema::dropIfExists('users'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/migrations/2014_10_12_100000_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token')->index(); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/migrations/2017_03_13_105849_create_articles_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('title', 100); 19 | $table->text('body'); 20 | $table->timestamps(); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('articles'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/seeds/ArticleSeeder.php: -------------------------------------------------------------------------------- 1 | 'Article 1', 'body' => 'Lorem ipsum dolor sit amet'], 11 | ['title' => 'Article 2', 'body' => 'Lorem ipsum dolor sit amet'], 12 | ['title' => 'Article 3', 'body' => 'Lorem ipsum dolor sit amet'], 13 | ['title' => 'Article 4', 'body' => 'Lorem ipsum dolor sit amet'], 14 | ['title' => 'Article 5', 'body' => 'Lorem ipsum dolor sit amet'] 15 | ]; 16 | 17 | 18 | /** 19 | * Run the database seeds. 20 | * 21 | * @return void 22 | */ 23 | public function run() 24 | { 25 | if (Article::all()->count() > 0) { 26 | return; 27 | } 28 | 29 | foreach ($this->articles as $article) { 30 | $new = new Article; 31 | $new->title = $article['title']; 32 | $new->body = $article['body']; 33 | $new->save(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/database/seeds/DatabaseSeeder.php: -------------------------------------------------------------------------------- 1 | call(ArticleSeeder::class); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 5 | "watch": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 6 | "watch-poll": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --watch-poll --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js", 7 | "hot": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js", 8 | "production": "node node_modules/cross-env/bin/cross-env.js NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js" 9 | }, 10 | "devDependencies": { 11 | "axios": "^0.15.3", 12 | "bootstrap-sass": "^3.3.7", 13 | "jquery": "^3.1.1", 14 | "laravel-mix": "^0.8.1", 15 | "lodash": "^4.17.4", 16 | "vue": "^2.1.10" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 13 | ./tests/Feature 14 | 15 | 16 | 17 | ./tests/Unit 18 | 19 | 20 | 21 | 22 | ./app 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Redirect Trailing Slashes If Not A Folder... 9 | RewriteCond %{REQUEST_FILENAME} !-d 10 | RewriteRule ^(.*)/$ /$1 [L,R=301] 11 | 12 | # Handle Front Controller... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_FILENAME} !-f 15 | RewriteRule ^ index.php [L] 16 | 17 | # Handle Authorization Header 18 | RewriteCond %{HTTP:Authorization} . 19 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 20 | 21 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/laravel/public/favicon.ico -------------------------------------------------------------------------------- /examples/tutorials/laravel/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/public/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/assets/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * First we will load all of this project's JavaScript dependencies which 4 | * includes Vue and other libraries. It is a great starting point when 5 | * building robust, powerful web applications using Vue and Laravel. 6 | */ 7 | 8 | require('./bootstrap'); 9 | 10 | /** 11 | * Next, we will create a fresh Vue application instance and attach it to 12 | * the page. Then, you may begin adding components to this application 13 | * or customize the JavaScript scaffolding to fit your unique needs. 14 | */ 15 | 16 | Vue.component('example', require('./components/Example.vue')); 17 | 18 | const app = new Vue({ 19 | el: '#app' 20 | }); 21 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/assets/js/bootstrap.js: -------------------------------------------------------------------------------- 1 | 2 | window._ = require('lodash'); 3 | 4 | /** 5 | * We'll load jQuery and the Bootstrap jQuery plugin which provides support 6 | * for JavaScript based Bootstrap features such as modals and tabs. This 7 | * code may be modified to fit the specific needs of your application. 8 | */ 9 | 10 | window.$ = window.jQuery = require('jquery'); 11 | 12 | require('bootstrap-sass'); 13 | 14 | /** 15 | * Vue is a modern JavaScript library for building interactive web interfaces 16 | * using reactive data binding and reusable components. Vue's API is clean 17 | * and simple, leaving you to focus on building your next great project. 18 | */ 19 | 20 | window.Vue = require('vue'); 21 | 22 | /** 23 | * We'll load the axios HTTP library which allows us to easily issue requests 24 | * to our Laravel back-end. This library automatically handles sending the 25 | * CSRF token as a header based on the value of the "XSRF" token cookie. 26 | */ 27 | 28 | window.axios = require('axios'); 29 | 30 | window.axios.defaults.headers.common = { 31 | 'X-CSRF-TOKEN': window.Laravel.csrfToken, 32 | 'X-Requested-With': 'XMLHttpRequest' 33 | }; 34 | 35 | /** 36 | * Echo exposes an expressive API for subscribing to channels and listening 37 | * for events that are broadcast by Laravel. Echo and event broadcasting 38 | * allows your team to easily build robust real-time web applications. 39 | */ 40 | 41 | // import Echo from "laravel-echo" 42 | 43 | // window.Echo = new Echo({ 44 | // broadcaster: 'pusher', 45 | // key: 'your-pusher-key' 46 | // }); 47 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/assets/js/components/Example.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 24 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/assets/sass/_variables.scss: -------------------------------------------------------------------------------- 1 | 2 | // Body 3 | $body-bg: #f5f8fa; 4 | 5 | // Borders 6 | $laravel-border-color: darken($body-bg, 10%); 7 | $list-group-border: $laravel-border-color; 8 | $navbar-default-border: $laravel-border-color; 9 | $panel-default-border: $laravel-border-color; 10 | $panel-inner-border: $laravel-border-color; 11 | 12 | // Brands 13 | $brand-primary: #3097D1; 14 | $brand-info: #8eb4cb; 15 | $brand-success: #2ab27b; 16 | $brand-warning: #cbb956; 17 | $brand-danger: #bf5329; 18 | 19 | // Typography 20 | $icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/"; 21 | $font-family-sans-serif: "Raleway", sans-serif; 22 | $font-size-base: 14px; 23 | $line-height-base: 1.6; 24 | $text-color: #636b6f; 25 | 26 | // Navbar 27 | $navbar-default-bg: #fff; 28 | 29 | // Buttons 30 | $btn-default-color: $text-color; 31 | 32 | // Inputs 33 | $input-border: lighten($text-color, 40%); 34 | $input-border-focus: lighten($brand-primary, 25%); 35 | $input-color-placeholder: lighten($text-color, 30%); 36 | 37 | // Panels 38 | $panel-default-heading-bg: #fff; 39 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/assets/sass/app.scss: -------------------------------------------------------------------------------- 1 | 2 | // Fonts 3 | @import url(https://fonts.googleapis.com/css?family=Raleway:300,400,600); 4 | 5 | // Variables 6 | @import "variables"; 7 | 8 | // Bootstrap 9 | @import "node_modules/bootstrap-sass/assets/stylesheets/bootstrap"; 10 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Passwords must be at least six characters and match the confirmation.', 17 | 'reset' => 'Your password has been reset!', 18 | 'sent' => 'We have e-mailed your password reset link!', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that e-mail address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/views/article/create.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |

Create Article

8 | @include('common.errors') 9 |
10 | {!! csrf_field() !!} 11 |
12 | 13 | 14 |
15 |
16 | 17 | 18 |
19 | 20 |
21 |
22 |
23 |
24 | @endsection 25 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/views/article/edit.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |

Edit Article

8 | @include('common.errors') 9 |
10 | {!! csrf_field() !!} 11 | {!! method_field('PUT') !!} 12 |
13 | 14 | 16 |
17 |
18 | 19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 | @endsection 27 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/views/article/show.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |

{{ $article->title }}

8 |

{{ $article->body }}

9 |
10 |
11 |
12 | @endsection 13 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/views/common/errors.blade.php: -------------------------------------------------------------------------------- 1 | @if (count($errors) > 0) 2 |
3 |
    4 | @foreach ($errors->all() as $error) 5 |
  • {{ $error }}
  • 6 | @endforeach 7 |
8 |
9 | @endif 10 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/resources/views/home.blade.php: -------------------------------------------------------------------------------- 1 | @extends('layouts.app') 2 | 3 | @section('content') 4 |
5 |
6 |
7 |
8 |
Dashboard
9 | 10 |
11 | You are logged in! 12 |
13 |
14 |
15 |
16 |
17 | @endsection 18 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/routes/api.php: -------------------------------------------------------------------------------- 1 | get('/user', function (Request $request) { 17 | return $request->user(); 18 | }); 19 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 16 | }); 17 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 18 | })->describe('Display an inspiring quote'); 19 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/routes/web.php: -------------------------------------------------------------------------------- 1 | 8 | */ 9 | 10 | $uri = urldecode( 11 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 12 | ); 13 | 14 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 15 | // built-in PHP web server. This provides a convenient way to test a Laravel 16 | // application without having installed a "real" web server software here. 17 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 18 | return false; 19 | } 20 | 21 | require_once __DIR__.'/public/index.php'; 22 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | config.php 2 | routes.php 3 | schedule-* 4 | compiled.php 5 | services.json 6 | events.scanned.php 7 | routes.scanned.php 8 | down 9 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/tests/Feature/ExampleTest.php: -------------------------------------------------------------------------------- 1 | get('/'); 20 | 21 | $response->assertStatus(200); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/tests/TestCase.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /examples/tutorials/laravel/webpack.mix.js: -------------------------------------------------------------------------------- 1 | const { mix } = require('laravel-mix'); 2 | 3 | /* 4 | |-------------------------------------------------------------------------- 5 | | Mix Asset Management 6 | |-------------------------------------------------------------------------- 7 | | 8 | | Mix provides a clean, fluent API for defining some Webpack build steps 9 | | for your Laravel application. By default, we are compiling the Sass 10 | | file for the application as well as bundling up all the JS files. 11 | | 12 | */ 13 | 14 | mix.js('resources/assets/js/app.js', 'public/js') 15 | .sass('resources/assets/sass/app.scss', 'public/css'); 16 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-journal 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore Byebug command history file. 21 | .byebug_history 22 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/app/assets/images/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. JavaScript code in this file should be added after the last require_* statement. 9 | // 10 | // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require_tree . 17 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/javascripts/articles.coffee: -------------------------------------------------------------------------------- 1 | # Place all the behaviors and hooks related to the matching controller here. 2 | # All this logic will automatically be available in application.js. 3 | # You can use CoffeeScript in this file: http://coffeescript.org/ 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the rails generate channel command. 3 | // 4 | //= require action_cable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/stylesheets/articles.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the articles controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: http://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/assets/stylesheets/scaffolds.scss: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #fff; 3 | color: #333; 4 | font-family: verdana, arial, helvetica, sans-serif; 5 | font-size: 13px; 6 | line-height: 18px; 7 | margin: 33px; 8 | } 9 | 10 | p, ol, ul, td { 11 | font-family: verdana, arial, helvetica, sans-serif; 12 | font-size: 13px; 13 | line-height: 18px; 14 | margin: 33px; 15 | } 16 | 17 | pre { 18 | background-color: #eee; 19 | padding: 10px; 20 | font-size: 11px; 21 | } 22 | 23 | a { 24 | color: #000; 25 | 26 | &:visited { 27 | color: #666; 28 | } 29 | 30 | &:hover { 31 | color: #fff; 32 | background-color: #000; 33 | } 34 | } 35 | 36 | th { 37 | padding-bottom: 5px; 38 | } 39 | 40 | td { 41 | padding-bottom: 7px; 42 | padding-left: 5px; 43 | padding-right: 5px; 44 | } 45 | 46 | div { 47 | &.field, &.actions { 48 | margin-bottom: 10px; 49 | } 50 | } 51 | 52 | #notice { 53 | color: green; 54 | } 55 | 56 | .field_with_errors { 57 | padding: 2px; 58 | background-color: red; 59 | display: table; 60 | } 61 | 62 | #error_explanation { 63 | width: 450px; 64 | border: 2px solid red; 65 | padding: 7px; 66 | padding-bottom: 0; 67 | margin-bottom: 20px; 68 | background-color: #f0f0f0; 69 | 70 | h2 { 71 | text-align: left; 72 | font-weight: bold; 73 | padding: 5px 5px 5px 15px; 74 | font-size: 12px; 75 | margin: -7px; 76 | margin-bottom: 0; 77 | background-color: #c00; 78 | color: #fff; 79 | } 80 | 81 | ul li { 82 | font-size: 12px; 83 | list-style: square; 84 | } 85 | } 86 | 87 | label { 88 | display: block; 89 | } 90 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | end 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/helpers/articles_helper.rb: -------------------------------------------------------------------------------- 1 | module ArticlesHelper 2 | end 3 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/models/article.rb: -------------------------------------------------------------------------------- 1 | class Article < ApplicationRecord 2 | end 3 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/app/models/concerns/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= form_for(article) do |f| %> 2 | <% if article.errors.any? %> 3 |
4 |

<%= pluralize(article.errors.count, "error") %> prohibited this article from being saved:

5 | 6 |
    7 | <% article.errors.full_messages.each do |message| %> 8 |
  • <%= message %>
  • 9 | <% end %> 10 |
11 |
12 | <% end %> 13 | 14 |
15 | <%= f.label :title %> 16 | <%= f.text_field :title %> 17 |
18 | 19 |
20 | <%= f.label :body %> 21 | <%= f.text_area :body %> 22 |
23 | 24 |
25 | <%= f.submit %> 26 |
27 | <% end %> 28 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Editing Article

2 | 3 | <%= render 'form', article: @article %> 4 | 5 | <%= link_to 'Show', @article %> | 6 | <%= link_to 'Back', articles_path %> 7 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/index.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 |

Articles

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | <% @articles.each do |article| %> 16 | <% cache article do %> 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | <% end %> 25 | <% end %> 26 | 27 |
TitleBody
<%= article.title %><%= article.body %><%= link_to 'Show', article %><%= link_to 'Edit', edit_article_path(article) %><%= link_to 'Destroy', article, method: :delete, data: { confirm: 'Are you sure?' } %>
28 | 29 |
30 | 31 | <%= link_to 'New Article', new_article_path %> 32 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/index.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.array!(@articles) do |article| 2 | json.extract! article, :id, :title, :body 3 | json.url article_url(article, format: :json) 4 | end 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Article

2 | 3 | <%= render 'form', article: @article %> 4 | 5 | <%= link_to 'Back', articles_path %> 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= notice %>

2 | 3 | <% cache @article do %> 4 |

5 | Title: 6 | <%= @article.title %> 7 |

8 | 9 |

10 | Body: 11 | <%= @article.body %> 12 |

13 | <% end %> 14 | 15 | <%= link_to 'Edit', edit_article_path(@article) %> | 16 | <%= link_to 'Back', articles_path %> 17 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/articles/show.json.jbuilder: -------------------------------------------------------------------------------- 1 | json.extract! @article, :id, :title, :body, :created_at, :updated_at 2 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Work 5 | <%= csrf_meta_tags %> 6 | 7 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 8 | <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path('../config/application', __dir__) 3 | require_relative '../config/boot' 4 | require 'rails/commands' 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative '../config/boot' 3 | require 'rake' 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # puts "\n== Copying sample files ==" 22 | # unless File.exist?('config/database.yml') 23 | # cp 'config/database.yml.sample', 'config/database.yml' 24 | # end 25 | 26 | puts "\n== Preparing database ==" 27 | system! 'bin/rails db:setup' 28 | 29 | puts "\n== Removing old logs and tempfiles ==" 30 | system! 'bin/rails log:clear tmp:clear' 31 | 32 | puts "\n== Restarting application server ==" 33 | system! 'bin/rails restart' 34 | end 35 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Work 10 | class Application < Rails::Application 11 | # Settings in config/environments/* take precedence over those specified here. 12 | # Application configuration should go into files in config/initializers 13 | # -- all .rb files in that directory are automatically loaded. 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Read the Rails 5.0 release notes for more info on each option. 6 | 7 | # Enable per-form CSRF tokens. Previous versions had false. 8 | Rails.application.config.action_controller.per_form_csrf_tokens = true 9 | 10 | # Enable origin-checking CSRF mitigation. Previous versions had false. 11 | Rails.application.config.action_controller.forgery_protection_origin_check = true 12 | 13 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 14 | # Previous versions had false. 15 | ActiveSupport.to_time_preserves_timezone = true 16 | 17 | # Require `belongs_to` associations by default. Previous versions had false. 18 | Rails.application.config.active_record.belongs_to_required_by_default = true 19 | 20 | # Do not halt callback chains when a callback returns false. Previous versions had true. 21 | ActiveSupport.halt_callback_chains_on_return_false = false 22 | 23 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false. 24 | Rails.application.config.ssl_options = { hsts: { subdomains: true } } 25 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_work_session' 4 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | root 'articles#index' 3 | resources :articles 4 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 5 | end 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 33ed5102358ea8a12d2e5ab5ff854cc67191961a0c8a1cbc57967d965a94f474e67c9579d786ac02e13b2b1ff74627ca5a6c879a8c8be34d2f2ba54179ebc616 15 | 16 | test: 17 | secret_key_base: 0a557bcec53ded5b725279914fb0ebe0510309d8578c379f6c5533b1448e654b9d342cc742ca421507e5e598b0a97bbe93518cd2d1965595015aeda374a51458 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | ).each { |path| Spring.watch(path) } 7 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/db/migrate/20160715112354_create_articles.rb: -------------------------------------------------------------------------------- 1 | class CreateArticles < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :articles do |t| 4 | t.string :title 5 | t.text :body 6 | 7 | t.timestamps 8 | end 9 | add_index :articles, :title 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 20160715112354) do 14 | 15 | # These are extensions that must be enabled in order to support this database 16 | enable_extension "plpgsql" 17 | 18 | create_table "articles", force: :cascade do |t| 19 | t.string "title" 20 | t.text "body" 21 | t.datetime "created_at", null: false 22 | t.datetime "updated_at", null: false 23 | t.index ["title"], name: "index_articles_on_title", using: :btree 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | 9 | if Article.count == 0 10 | Article.create([ 11 | { title: 'Article 1', body: 'Lorem ipsum dolor sit amet' }, 12 | { title: 'Article 2', body: 'Lorem ipsum dolor sit amet' }, 13 | { title: 'Article 3', body: 'Lorem ipsum dolor sit amet' } 14 | ]) 15 | end 16 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/lib/assets/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/lib/tasks/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/log/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/public/apple-touch-icon.png -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/public/favicon.ico -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/controllers/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/controllers/articles_controller_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ArticlesControllerTest < ActionDispatch::IntegrationTest 4 | setup do 5 | @article = articles(:one) 6 | end 7 | 8 | test "should get index" do 9 | get articles_url 10 | assert_response :success 11 | end 12 | 13 | test "should get new" do 14 | get new_article_url 15 | assert_response :success 16 | end 17 | 18 | test "should create article" do 19 | assert_difference('Article.count') do 20 | post articles_url, params: { article: { body: @article.body, title: @article.title } } 21 | end 22 | 23 | assert_redirected_to article_url(Article.last) 24 | end 25 | 26 | test "should show article" do 27 | get article_url(@article) 28 | assert_response :success 29 | end 30 | 31 | test "should get edit" do 32 | get edit_article_url(@article) 33 | assert_response :success 34 | end 35 | 36 | test "should update article" do 37 | patch article_url(@article), params: { article: { body: @article.body, title: @article.title } } 38 | assert_redirected_to article_url(@article) 39 | end 40 | 41 | test "should destroy article" do 42 | assert_difference('Article.count', -1) do 43 | delete article_url(@article) 44 | end 45 | 46 | assert_redirected_to articles_url 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/fixtures/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/fixtures/articles.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | title: MyString 5 | body: MyText 6 | 7 | two: 8 | title: MyString 9 | body: MyText 10 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/fixtures/files/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/helpers/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/integration/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/mailers/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/test/models/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/models/article_test.rb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | 3 | class ArticleTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/tmp/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /examples/tutorials/ruby_on_rails/vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/examples/tutorials/ruby_on_rails/vendor/assets/stylesheets/.keep -------------------------------------------------------------------------------- /examples/weblate/.gitignore: -------------------------------------------------------------------------------- 1 | /.vagga 2 | /data 3 | -------------------------------------------------------------------------------- /fetch_binaries.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh -ex 2 | ALPINE_VERSION=v3.15 3 | ALPINE_MIRROR=http://dl-cdn.alpinelinux.org/alpine/ 4 | APK_TOOLS=apk-tools-static-2.12.7-r3.apk 5 | BUSYBOX=busybox-static-1.34.1-r3.apk 6 | ALPINE_KEYS=alpine-keys-2.4-r1.apk 7 | 8 | ARCH=${1:-x86_64} 9 | 10 | SHA1SUMS_x86_64="\ 11 | 2fa49548020eb850e0a15df03471a07eba55fbc8 $APK_TOOLS 12 | 83a302a36b2239669130d459b14619d066d37f22 $BUSYBOX 13 | 7dba809ae84d5832473f9cbf3bc6522d341299ca $ALPINE_KEYS" 14 | 15 | SHA1SUMS_armhf="\ 16 | 49fd9c34731593f5753fbc100dbb344e3f22cf47 $APK_TOOLS 17 | 06bd6d50070251de09f34dd37ebbeb17aa014db8 $BUSYBOX 18 | 1c45ddb6ae0a0aee7793505cce4fcee0d82c7ac1 $ALPINE_KEYS" 19 | 20 | FETCH_DIR="alpine/"$ARCH 21 | mkdir -p "$FETCH_DIR" 2>/dev/null || true 22 | cd "$FETCH_DIR" 23 | 24 | for pkg in $APK_TOOLS $BUSYBOX $ALPINE_KEYS; do 25 | wget --no-use-server-timestamp ${ALPINE_MIRROR}${ALPINE_VERSION}/main/$ARCH/$pkg -O $pkg 26 | done 27 | 28 | sha1sum $APK_TOOLS 29 | sha1sum $BUSYBOX 30 | sha1sum $ALPINE_KEYS 31 | SUMS="SHA1SUMS_$ARCH" 32 | eval "SUMS=\$$SUMS" 33 | echo "$SUMS" | sha1sum -c - 34 | 35 | cd ../.. 36 | 37 | tar -xOf "$FETCH_DIR/$APK_TOOLS" sbin/apk.static > apk 38 | tar -xOf "$FETCH_DIR/$BUSYBOX" bin/busybox.static > busybox 39 | cp "$FETCH_DIR/$ALPINE_KEYS" alpine-keys.apk 40 | 41 | chmod +x apk busybox 42 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | DESTDIR=${DESTDIR:-} 3 | PREFIX=${PREFIX:-/usr} 4 | 5 | install -d ${DESTDIR}/etc/bash_completion.d 6 | install -d ${DESTDIR}${PREFIX}/share/zsh/site-functions 7 | install -d ${DESTDIR}${PREFIX}/bin 8 | install -d ${DESTDIR}${PREFIX}/lib/vagga 9 | install -m 644 completions/bash-completion.sh ${DESTDIR}/etc/bash_completion.d/vagga 10 | install -m 644 completions/zsh-completion.sh ${DESTDIR}${PREFIX}/share/zsh/site-functions/_vagga 11 | install -m 755 vagga ${DESTDIR}${PREFIX}/lib/vagga/vagga 12 | install -m 755 apk ${DESTDIR}${PREFIX}/lib/vagga/apk 13 | install -m 755 busybox ${DESTDIR}${PREFIX}/lib/vagga/busybox 14 | install -m 755 alpine-keys.apk ${DESTDIR}${PREFIX}/lib/vagga/alpine-keys.apk 15 | ln -snf ../lib/vagga/vagga ${DESTDIR}${PREFIX}/bin/vagga 16 | -------------------------------------------------------------------------------- /path_filter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "path-filter" 3 | version = "0.1.0" 4 | license = "MIT/Apache-2.0" 5 | edition = "2021" 6 | 7 | [dependencies] 8 | globset = "0.4.1" 9 | quick-error = "1.1.0" 10 | regex = "1" 11 | walkdir = "2" 12 | -------------------------------------------------------------------------------- /path_filter/tests/dir1/dir/subdir/test.ini: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/path_filter/tests/dir1/dir/subdir/test.ini -------------------------------------------------------------------------------- /path_filter/tests/dir1/dir/test.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/path_filter/tests/dir1/dir/test.py -------------------------------------------------------------------------------- /path_filter/tests/dir1/dir/test.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/path_filter/tests/dir1/dir/test.rs -------------------------------------------------------------------------------- /path_filter/tests/dir1/test.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/path_filter/tests/dir1/test.py -------------------------------------------------------------------------------- /path_filter/tests/dir1/test.rs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tailhook/vagga/275b540cec12a1c721c121be58cf5a6d63fa8863/path_filter/tests/dir1/test.rs -------------------------------------------------------------------------------- /src/build_step.rs: -------------------------------------------------------------------------------- 1 | use std::rc::Rc; 2 | use std::fmt::Debug; 3 | 4 | use mopa::mopafy; 5 | 6 | // Convenient reexports 7 | pub use crate::builder::{Guard, StepError}; 8 | pub use crate::config::Config; 9 | pub use crate::digest::Digest; 10 | pub use crate::version::{Error as VersionError}; 11 | 12 | #[derive(Clone, Debug)] 13 | pub struct Step(pub Rc); 14 | 15 | mopafy!(BuildStep); 16 | 17 | pub trait BuildStep: ::mopa::Any + Debug { 18 | fn name(&self) -> &'static str; 19 | #[cfg(feature="containers")] 20 | fn hash(&self, cfg: &Config, hash: &mut Digest) 21 | -> Result<(), VersionError>; 22 | #[cfg(feature="containers")] 23 | fn build(&self, guard: &mut Guard, build: bool) 24 | -> Result<(), StepError>; 25 | fn is_dependent_on(&self) -> Option<&str>; 26 | } 27 | 28 | impl BuildStep for Step { 29 | fn name(&self) -> &'static str { 30 | self.0.name() 31 | } 32 | #[cfg(feature="containers")] 33 | fn hash(&self, cfg: &Config, hash: &mut Digest) 34 | -> Result<(), VersionError> 35 | { 36 | self.0.hash(cfg, hash) 37 | } 38 | #[cfg(feature="containers")] 39 | fn build(&self, guard: &mut Guard, build: bool) 40 | -> Result<(), StepError> 41 | { 42 | self.0.build(guard, build) 43 | } 44 | fn is_dependent_on(&self) -> Option<&str> 45 | { 46 | self.0.is_dependent_on() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/builder/dns.rs: -------------------------------------------------------------------------------- 1 | use std::fs::symlink_metadata; 2 | 3 | use crate::file_util::copy; 4 | 5 | /// Reverts resolv.conf and hosts files after they might be replaces by 6 | /// come container unpacking or copying 7 | pub fn revert_name_files() -> Result<(), String> { 8 | 9 | let md = symlink_metadata("/vagga/root/etc/resolv.conf"); 10 | if md.is_err() || matches!(md, Ok(ref t) if t.is_file()) { 11 | copy("/etc/resolv.conf", "/vagga/root/etc/resolv.conf") 12 | .map_err(|e| format!("Error copying /etc/resolv.conf: {}", e))?; 13 | } else { 14 | warn!("The `/etc/resolv.conf` is not a file, we avoid replacing it. \ 15 | Under certain conditions this may mean that DNS does not work \ 16 | in the container.") 17 | } 18 | 19 | let md = symlink_metadata("/vagga/root/etc/hosts"); 20 | if md.is_err() || matches!(md, Ok(ref t) if t.is_file()) { 21 | copy("/etc/hosts", "/vagga/root/etc/hosts") 22 | .map_err(|e| format!("Error copying /etc/hosts: {}", e))?; 23 | } else { 24 | warn!("The `/etc/hosts` is not a file, we avoid replacing it. \ 25 | Under certain conditions this may mean that DNS works badly \ 26 | in the container.") 27 | } 28 | 29 | Ok(()) 30 | } 31 | -------------------------------------------------------------------------------- /src/builder/timer.rs: -------------------------------------------------------------------------------- 1 | use std::io::Error; 2 | use std::io::Write; 3 | use std::path::Path; 4 | use std::fs::File; 5 | use std::fmt::{Arguments}; 6 | use std::time::{Instant, Duration, SystemTime, UNIX_EPOCH}; 7 | 8 | const NANO_FACTOR: f64 = 0.000000001; 9 | 10 | 11 | fn duration_as_f64(d: Duration) -> f64 { 12 | (d.as_secs() as f64) + (NANO_FACTOR * d.subsec_nanos() as f64) 13 | } 14 | 15 | pub struct TimeLog { 16 | file: File, 17 | start: Instant, 18 | prev: Instant, 19 | } 20 | 21 | impl TimeLog { 22 | pub fn start(path: &Path) -> Result { 23 | let now = SystemTime::now(); 24 | let now_instant = Instant::now(); 25 | let mut res = TimeLog { 26 | file: File::create(path)?, 27 | start: now_instant, 28 | prev: now_instant, 29 | }; 30 | let duration = now.duration_since(UNIX_EPOCH) 31 | .expect("FATAL: now was created after the epoch"); 32 | res.mark(format_args!("Start {:?}", duration_as_f64(duration)))?; 33 | Ok(res) 34 | } 35 | pub fn mark(&mut self, args: Arguments) -> Result<(), Error> { 36 | let now = Instant::now(); 37 | let d_start = duration_as_f64(now.duration_since(self.start)); 38 | let d_prev = duration_as_f64(now.duration_since(self.prev)); 39 | write!(&mut self.file, "{:7.3} {:7.3} ", d_start, d_prev) 40 | .and_then(|()| self.file.write_fmt(args)) 41 | .and_then(|()| writeln!(&mut self.file, "")) 42 | .map(|()| self.prev = now) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/capsule/build.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdout, stderr}; 2 | 3 | use argparse::{ArgumentParser, Store, StoreTrue}; 4 | 5 | use crate::capsule::Context; 6 | use crate::launcher::build::build_container; 7 | 8 | 9 | pub fn build_command(context: &Context, args: Vec) 10 | -> Result 11 | { 12 | let mut name: String = "".to_string(); 13 | let mut force: bool = false; 14 | let mut print_version: bool = false; 15 | { 16 | let mut cmdline = args.clone(); 17 | cmdline.insert(0, String::from("vagga _capsule build")); 18 | let mut ap = ArgumentParser::new(); 19 | ap.set_description(" 20 | Internal vagga tool to setup basic system sandbox 21 | "); 22 | ap.refer(&mut name) 23 | .add_argument("container_name", Store, 24 | "Container name to build"); 25 | ap.refer(&mut force) 26 | .add_option(&["--force"], StoreTrue, 27 | "Force build even if container is considered up to date"); 28 | ap.refer(&mut print_version) 29 | .add_option(&["--print-version"], StoreTrue, 30 | "Print version number to stdout after building"); 31 | match ap.parse(cmdline, &mut stdout(), &mut stderr()) { 32 | Ok(()) => {} 33 | Err(0) => return Ok(0), 34 | Err(_) => { 35 | return Ok(122); 36 | } 37 | } 38 | } 39 | build_container(context, &name, context.build_mode, true) 40 | .map(|version| { 41 | debug!("Container {:?} is built with version {:?}", name, version); 42 | if print_version { 43 | println!("{}", version); 44 | } 45 | }) 46 | .map(|()| 0) 47 | } 48 | -------------------------------------------------------------------------------- /src/capsule/mod.rs: -------------------------------------------------------------------------------- 1 | mod build; 2 | mod run; 3 | mod script; 4 | pub mod packages; 5 | pub mod download; 6 | 7 | use std::io::{Write, stdout, stderr}; 8 | 9 | use argparse::{ArgumentParser, Store, List}; 10 | 11 | use crate::launcher; 12 | 13 | pub use self::packages::State; 14 | 15 | 16 | pub type Context = launcher::Context; 17 | 18 | pub fn run_command(context: &Context, mut input_args: Vec) 19 | -> Result 20 | { 21 | let mut args = Vec::::new(); 22 | let mut cname = "".to_string(); 23 | { 24 | let mut ap = ArgumentParser::new(); 25 | ap.set_description(" 26 | Run a special capsule command. Only can be run from inside the 27 | `!CapsuleCommand` handler. 28 | "); 29 | ap.refer(&mut cname) 30 | .add_argument("command", Store, 31 | "A command to run: only `build` supported so far"); 32 | ap.refer(&mut args) 33 | .add_argument("args", List, 34 | "Arguments for the command"); 35 | ap.stop_on_first_argument(true); 36 | input_args.insert(0, String::from("vagga _capsule")); 37 | match ap.parse(input_args, &mut stdout(), &mut stderr()) { 38 | Ok(()) => {} 39 | Err(0) => return Ok(0), 40 | Err(_) => return Ok(122), 41 | } 42 | } 43 | match &cname[..] { 44 | "build" => build::build_command(context, args), 45 | "version" => build::build_command(context, args), 46 | "run" => run::run_command(context, args), 47 | "script" => script::run_script(context, args), 48 | "download" => download::run_download(context, args), 49 | _ => { 50 | writeln!(&mut stderr(), "Unknown command {:?}", cname).ok(); 51 | Ok(127) 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/config/mod.rs: -------------------------------------------------------------------------------- 1 | pub use self::settings::Settings; 2 | pub use self::containers::{Container}; 3 | pub use self::range::Range; 4 | pub use self::config::{Config, read_config, find_config, find_config_or_exit}; 5 | pub use self::config::{ConfigError}; 6 | 7 | pub mod settings; 8 | pub mod read_settings; 9 | pub mod containers; 10 | pub mod range; 11 | pub mod builders; 12 | pub mod config; 13 | pub mod command; 14 | pub mod validate; 15 | pub mod version; 16 | pub mod volumes; 17 | -------------------------------------------------------------------------------- /src/config/range.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | 3 | use libc::uid_t; 4 | use serde::de::{Deserializer, Deserialize, Error}; 5 | 6 | 7 | #[derive(Clone, Debug, Copy, PartialEq, Eq, Serialize)] 8 | pub struct Range { 9 | start: uid_t, 10 | end: uid_t, 11 | } 12 | 13 | trait StringError { 14 | fn create_error(&self, value: String) -> T; 15 | } 16 | 17 | impl<'a> Deserialize<'a> for Range { 18 | fn deserialize>(d: D) -> Result { 19 | let val = String::deserialize(d)?; 20 | FromStr::from_str(&val[..]) 21 | .map(|num| Range::new(num, num)) 22 | .or_else(|_| { 23 | let mut pair = val.splitn(2, '-'); 24 | Ok(Range::new( 25 | pair.next().and_then(|x| FromStr::from_str(x).ok()) 26 | .ok_or(D::Error::custom("Error parsing range"))?, 27 | pair.next().and_then(|x| FromStr::from_str(x).ok()) 28 | .ok_or(D::Error::custom("Error parsing range"))?, 29 | )) 30 | }) 31 | } 32 | } 33 | 34 | impl Range { 35 | pub fn new(start: uid_t, end: uid_t) -> Range { 36 | assert!(end >= start); 37 | return Range { start: start, end: end+1 }; 38 | } 39 | pub fn len(&self) -> uid_t { 40 | return self.end - self.start; 41 | } 42 | pub fn shift(&self, val: uid_t) -> Range { 43 | assert!(self.end - self.start >= val); 44 | return Range { start: self.start + val, end: self.end }; 45 | } 46 | pub fn start(&self) -> uid_t { 47 | self.start 48 | } 49 | pub fn end(&self) -> uid_t { 50 | self.end 51 | } 52 | } 53 | 54 | -------------------------------------------------------------------------------- /src/config/settings.rs: -------------------------------------------------------------------------------- 1 | use std::str::FromStr; 2 | use std::collections::BTreeMap; 3 | 4 | use libc::{uid_t, gid_t}; 5 | use serde_json; 6 | 7 | 8 | const DEFAULT_UBUNTU_MIRROR: &str = "mirror://mirrors.ubuntu.com/mirrors.txt"; 9 | 10 | const DEFAULT_ALPINE_MIRROR: &str = "http://dl-cdn.alpinelinux.org/alpine/"; 11 | 12 | #[derive(Deserialize, Serialize, Default, Clone, Debug)] 13 | pub struct Settings { 14 | pub version_check: bool, 15 | pub proxy_env_vars: bool, 16 | pub ubuntu_mirror: Option, 17 | pub ubuntu_skip_locking: bool, 18 | pub alpine_mirror: Option, 19 | pub uid_map: Option<(Vec<(uid_t, uid_t, uid_t)>, 20 | Vec<(gid_t, gid_t, gid_t)>)>, 21 | pub push_image_script: Option, 22 | pub build_lock_wait: bool, 23 | pub versioned_build_dir: bool, 24 | pub auto_apply_sysctl: bool, 25 | pub environ: BTreeMap, 26 | pub index_all_images: bool, 27 | pub hard_link_identical_files: bool, 28 | pub hard_link_between_projects: bool, 29 | pub run_symlinks_as_commands: bool, 30 | pub disable_auto_clean: bool, 31 | pub storage_subdir_from_env_var: Option, 32 | } 33 | 34 | impl Settings { 35 | pub fn ubuntu_mirror(&self) -> &str { 36 | self.ubuntu_mirror.as_ref().map(|m| m.as_str()) 37 | .unwrap_or(DEFAULT_UBUNTU_MIRROR) 38 | } 39 | 40 | pub fn alpine_mirror(&self) -> &str { 41 | self.alpine_mirror.as_ref().map(|m| m.as_str()) 42 | .unwrap_or(DEFAULT_ALPINE_MIRROR) 43 | } 44 | } 45 | 46 | impl FromStr for Settings { 47 | type Err = (); 48 | fn from_str(val: &str) -> Result { 49 | serde_json::from_str(val).map_err(|_| ()) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/config/validate.rs: -------------------------------------------------------------------------------- 1 | use crate::build_step::Step; 2 | 3 | use super::Config; 4 | use super::containers::Container; 5 | 6 | fn find_name(name: &str, cont: &Container, cfg: &Config) -> Result<(), String> 7 | { 8 | for &Step(ref step) in &cont.setup { 9 | if let Some(subname) = step.is_dependent_on() { 10 | if subname == name { 11 | return Err(format!("Container {:?} has cyclic dependency", 12 | name)); 13 | } else { 14 | let subcont = cfg.containers.get(subname) 15 | .ok_or(format!("Container {:?} referenced from {:?} \ 16 | is not found", subname, name))?; 17 | find_name(name, subcont, cfg)? 18 | } 19 | } 20 | } 21 | Ok(()) 22 | } 23 | 24 | pub fn validate_container(name: &str, cont: &Container, cfg: &Config) 25 | -> Result<(), String> 26 | { 27 | find_name(name, cont, cfg)?; 28 | Ok(()) 29 | } 30 | 31 | pub fn validate_config(cfg: &Config) -> Result<(), String> { 32 | for (ref cname, ref cont) in &cfg.containers { 33 | validate_container(cname, cont, cfg)?; 34 | } 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /src/container/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod util; 2 | 3 | pub mod uidmap; 4 | pub mod mount; 5 | pub mod root; 6 | pub mod nsutil; 7 | pub mod network; 8 | -------------------------------------------------------------------------------- /src/container/network.rs: -------------------------------------------------------------------------------- 1 | use std::fs::File; 2 | use std::io::Read; 3 | use std::path::Path; 4 | 5 | use failure::{Error, ResultExt}; 6 | use resolv_conf::{self, ScopedIp}; 7 | 8 | 9 | pub fn get_nameservers() -> Result, Error> { 10 | let mut buf = Vec::with_capacity(1024); 11 | File::open(&Path::new("/etc/resolv.conf")) 12 | .and_then(|mut f| f.read_to_end(&mut buf)) 13 | .context("error reading resolv.conf")?; 14 | let config = resolv_conf::Config::parse(&buf) 15 | .context("error reading resolv.conf")?; 16 | return Ok(config.nameservers); 17 | } 18 | 19 | pub fn detect_local_dns() -> Result, Error> { 20 | let nameservers = get_nameservers()?; 21 | info!("Detected nameservers: {:?}", nameservers); 22 | 23 | let local_dns = match nameservers.first() { 24 | Some(&ScopedIp::V4(ip)) 25 | if nameservers.len() == 1 && ip.octets()[..3] == [127, 0, 0] 26 | => Some(ip.to_string()), 27 | _ => None, 28 | }; 29 | Ok(local_dns) 30 | } 31 | -------------------------------------------------------------------------------- /src/launcher/integration.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdout, stderr}; 2 | 3 | use argparse::{ArgumentParser, StoreTrue}; 4 | use serde_json; 5 | 6 | use crate::config::Config; 7 | 8 | 9 | pub fn dump_config(config: &Config, mut args: Vec) 10 | -> Result 11 | { 12 | let mut pretty = false; 13 | { 14 | args.insert(0, String::from("vagga _dump_config")); 15 | let mut ap = ArgumentParser::new(); 16 | ap.refer(&mut pretty) 17 | .add_option(&["--pretty"], StoreTrue, 18 | "Prettify printed json"); 19 | match ap.parse(args, &mut stdout(), &mut stderr()) { 20 | Ok(()) => {} 21 | Err(x) => return Ok(x), 22 | } 23 | } 24 | if pretty { 25 | println!("{}", serde_json::to_string_pretty(config) 26 | .expect("can serialize config")); 27 | } else { 28 | println!("{}", serde_json::to_string(config) 29 | .expect("can serialize config")); 30 | } 31 | return Ok(0); 32 | } 33 | -------------------------------------------------------------------------------- /src/launcher/pack.rs: -------------------------------------------------------------------------------- 1 | use unshare::Command; 2 | 3 | use crate::launcher::Context; 4 | use crate::launcher::build::build_container; 5 | use crate::launcher::wrap::Wrapper; 6 | use crate::options::pack::{Options}; 7 | use crate::process_util::convert_status; 8 | 9 | 10 | pub fn pack_command(context: &Context, args: Vec) 11 | -> Result 12 | { 13 | let mut cmdline = args.clone(); 14 | cmdline.insert(0, "vagga _pack_image".to_string()); 15 | let opt = match Options::parse(&cmdline) { 16 | Ok(x) => x, 17 | Err(code) => return Ok(code), 18 | }; 19 | 20 | let ver = build_container(context, &opt.name, opt.build_mode, false)?; 21 | 22 | let mut cmd: Command = Wrapper::new(Some(&ver), &context.settings); 23 | cmd.map_users_for( 24 | &context.config.get_container(&opt.name).unwrap(), 25 | &context.settings)?; 26 | cmd.gid(0); 27 | cmd.groups(Vec::new()); 28 | cmd.arg("_pack_image").args(&args); 29 | cmd.status().map(convert_status) 30 | .map_err(|e| format!("Error running `vagga_wrapperr _pack_image`: {}", e)) 31 | } 32 | -------------------------------------------------------------------------------- /src/launcher/socket.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use std::net::{TcpListener, SocketAddr, Ipv4Addr, ToSocketAddrs}; 3 | use std::net::{SocketAddrV4}; 4 | 5 | use net2::{TcpBuilder}; 6 | 7 | 8 | pub fn parse_and_bind(val: &str) -> io::Result { 9 | let addr = if let Ok(port) = val.parse() { 10 | SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), port)) 11 | } else { 12 | let mut parts = val.rsplitn(2, ':'); 13 | let port = match parts.next().and_then(|x| x.parse().ok()) { 14 | Some(x) => x, 15 | None => return Err(io::Error::new(io::ErrorKind::InvalidInput, 16 | "Can't parse port")), 17 | }; 18 | let host_str = parts.next() 19 | .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, 20 | "Address should be just `port`, or `host:port`"))?; 21 | if host_str == "*" { 22 | SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), port)) 23 | } else if let Ok(addr) = host_str.parse() { 24 | SocketAddr::new(addr, port) 25 | } else { 26 | // TODO(tailhook) use lookup_host 27 | (host_str, port).to_socket_addrs()? 28 | .next() 29 | .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, 30 | "Address could not be resolved"))? 31 | } 32 | }; 33 | let bld = match addr { 34 | SocketAddr::V4(..) => TcpBuilder::new_v4()?, 35 | SocketAddr::V6(..) => TcpBuilder::new_v6()?, 36 | }; 37 | bld.reuse_address(true)?; 38 | bld.bind(addr)?; 39 | bld.listen(128) // pretty standard value 40 | } 41 | -------------------------------------------------------------------------------- /src/launcher/storage_dir.rs: -------------------------------------------------------------------------------- 1 | use std::env; 2 | use std::path::PathBuf; 3 | 4 | use crate::launcher::Context; 5 | use crate::storage_dir::sanitize; 6 | 7 | 8 | pub fn get_base(ctx: &Context) -> Option { 9 | if let Some(ref storage_base) = ctx.ext_settings.storage_dir { 10 | let path = ctx.config_dir.join(".vagga/.lnk"); 11 | if !path.exists() { 12 | if let Some(ref v) = ctx.ext_settings.storage_subdir_from_env_var { 13 | if let Ok(value) = env::var(v) { 14 | let sanitized = sanitize(&value); 15 | Some(storage_base.join(sanitized)) 16 | } else { 17 | None 18 | } 19 | } else { 20 | None 21 | } 22 | } else { 23 | Some(path) // TODO(tailhook) or resolve the link? 24 | } 25 | } else { 26 | Some(ctx.config_dir.join(".vagga")) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/launcher/volumes.rs: -------------------------------------------------------------------------------- 1 | use crate::config::volumes::SnapshotInfo; 2 | use crate::config::volumes::Volume::{self, Container, Snapshot}; 3 | use crate::launcher::build::build_container; 4 | use crate::launcher::Context; 5 | 6 | 7 | pub fn prepare_volumes<'x, I>(volumes: I, context: &Context) 8 | -> Result<(), String> 9 | where I: Iterator 10 | { 11 | for v in volumes { 12 | match *v { 13 | Container(ref name) | 14 | Snapshot(SnapshotInfo { container: Some(ref name), .. }) => { 15 | build_container(context, name, context.build_mode, false)?; 16 | } 17 | _ => {} 18 | } 19 | } 20 | Ok(()) 21 | } 22 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! try_msg { 3 | ($op:expr, $message:expr) => ( 4 | ($op).map_err(|e| format!($message, err=e))? 5 | ); 6 | ($op:expr, $message:expr, $($key:ident=$value:expr),*) => ( 7 | ($op).map_err(|e| format!($message, err=e, $($key=$value),*))? 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /src/options/build_mode.rs: -------------------------------------------------------------------------------- 1 | use std::default::Default; 2 | 3 | use argparse::{ArgumentParser, StoreConst}; 4 | 5 | 6 | #[derive(Clone, Copy, Debug)] 7 | pub enum BuildMode { 8 | Normal, 9 | NoImage, 10 | NoBuild, 11 | NoVersion, 12 | } 13 | 14 | impl Default for BuildMode { 15 | fn default() -> BuildMode { 16 | BuildMode::Normal 17 | } 18 | } 19 | 20 | pub fn build_mode<'x>(ap: &mut ArgumentParser<'x>, mode: &'x mut BuildMode) 21 | { 22 | ap.refer(mode) 23 | .add_option(&["--no-image-download"], StoreConst(BuildMode::NoImage), " 24 | Do not download container image from image index. 25 | ") 26 | .add_option(&["--no-build"], StoreConst(BuildMode::NoBuild), " 27 | Do not build container even if it is out of date. Return error 28 | code 29 if it's out of date.") 29 | .add_option(&["--no-version-check"], StoreConst(BuildMode::NoVersion), " 30 | Do not run versioning code, just pick whatever container 31 | version with the name was run last (or actually whatever is 32 | symlinked under `.vagga/container_name`). Implies `--no-build` 33 | "); 34 | } 35 | -------------------------------------------------------------------------------- /src/options/compression_type.rs: -------------------------------------------------------------------------------- 1 | use argparse::{ArgumentParser, StoreConst}; 2 | 3 | #[cfg(feature="containers")] 4 | use crate::capsule::packages as capsule; 5 | 6 | 7 | #[derive(Clone, Copy, Debug)] 8 | pub enum CompressionType { 9 | Gzip, 10 | Bzip2, 11 | Xz, 12 | } 13 | 14 | impl CompressionType { 15 | pub fn get_short_option(&self) -> &str { 16 | match *self { 17 | CompressionType::Gzip => "-z", 18 | CompressionType::Bzip2 => "-j", 19 | CompressionType::Xz => "-J", 20 | } 21 | } 22 | 23 | #[cfg(feature="containers")] 24 | pub fn get_capsule_feature(&self) -> capsule::Feature { 25 | match *self { 26 | CompressionType::Gzip => capsule::Gzip, 27 | CompressionType::Bzip2 => capsule::Bzip2, 28 | CompressionType::Xz => capsule::Xz, 29 | } 30 | } 31 | } 32 | 33 | pub fn compression_type<'x>(ap: &mut ArgumentParser<'x>, 34 | compression_type: &'x mut Option) 35 | { 36 | ap.refer(compression_type) 37 | .add_option(&["-z", "--gzip"], StoreConst(Some(CompressionType::Gzip)), 38 | "Filter the image through gzip.") 39 | .add_option(&["-j", "--bzip2"], StoreConst(Some(CompressionType::Bzip2)), 40 | "Filter the image through bzip2.") 41 | .add_option(&["-J", "--xz"], StoreConst(Some(CompressionType::Xz)), 42 | "Filter the image through xz."); 43 | } 44 | -------------------------------------------------------------------------------- /src/options/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod build_mode; 2 | pub mod compression_type; 3 | pub mod pack; 4 | pub mod push; 5 | pub mod version_hash; 6 | -------------------------------------------------------------------------------- /src/options/pack.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdout, stderr}; 2 | use std::path::PathBuf; 3 | 4 | use argparse::{ArgumentParser, Store, ParseOption}; 5 | use super::build_mode::{build_mode, BuildMode}; 6 | use super::compression_type::{compression_type, CompressionType}; 7 | 8 | 9 | pub struct Options { 10 | pub name: String, 11 | pub file: Option, 12 | pub compression_type: Option, 13 | pub build_mode: BuildMode, 14 | } 15 | 16 | impl Options { 17 | pub fn parse(args: &Vec) -> Result { 18 | let mut opt = Options { 19 | name: "".to_string(), 20 | file: None, 21 | compression_type: None, 22 | build_mode: BuildMode::NoImage, 23 | }; 24 | { 25 | let mut ap = ArgumentParser::new(); 26 | ap.set_description(" 27 | Packs image into tar archive. 28 | 29 | Unfortunately compression is not supported yet. It's 30 | recommended to stream archive to compressor. 31 | "); 32 | ap.refer(&mut opt.name) 33 | .add_argument("container_name", Store, 34 | "Container name to pack"); 35 | ap.refer(&mut opt.file) 36 | .add_option(&["-f", "--file"], ParseOption, 37 | "File to store tar archive at"); 38 | compression_type(&mut ap, &mut opt.compression_type); 39 | build_mode(&mut ap, &mut opt.build_mode); 40 | match ap.parse(args.clone(), &mut stdout(), &mut stderr()) { 41 | Ok(()) => {} 42 | Err(0) => return Err(0), 43 | Err(_) => { 44 | return Err(122); 45 | } 46 | } 47 | } 48 | Ok(opt) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/options/push.rs: -------------------------------------------------------------------------------- 1 | use std::io::{stdout, stderr}; 2 | 3 | use argparse::{ArgumentParser, Store}; 4 | use super::build_mode::{build_mode, BuildMode}; 5 | 6 | 7 | pub struct Options { 8 | pub name: String, 9 | pub image_index_url: Option, 10 | pub build_mode: BuildMode, 11 | } 12 | 13 | impl Options { 14 | pub fn parse(args: &Vec) -> Result { 15 | let mut opt = Options { 16 | name: "".to_string(), 17 | image_index_url: None, 18 | build_mode: BuildMode::NoImage, 19 | }; 20 | { 21 | let mut ap = ArgumentParser::new(); 22 | ap.set_description(" 23 | Packs image into tar archive. 24 | 25 | Unfortunately compression is not supported yet. It's 26 | recommended to stream archive to compressor. 27 | "); 28 | ap.refer(&mut opt.name) 29 | .add_argument("container_name", Store, 30 | "Container name to pack"); 31 | build_mode(&mut ap, &mut opt.build_mode); 32 | match ap.parse(args.clone(), &mut stdout(), &mut stderr()) { 33 | Ok(()) => {} 34 | Err(0) => return Err(0), 35 | Err(_) => { 36 | return Err(122); 37 | } 38 | } 39 | } 40 | Ok(opt) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/storage_dir.rs: -------------------------------------------------------------------------------- 1 | use regex::Regex; 2 | 3 | use lazy_static::lazy_static; 4 | 5 | 6 | lazy_static! { 7 | static ref DIR_REPLACE_RE: Regex = Regex::new("[^a-zA-Z0-9_-]+").unwrap(); 8 | } 9 | 10 | pub fn sanitize(original: &str) -> String { 11 | DIR_REPLACE_RE.replace(original, "-").to_string() 12 | } 13 | -------------------------------------------------------------------------------- /src/version/error.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | use failure::{Error as FatalError, err_msg}; 3 | use std::path::Path; 4 | 5 | 6 | /// Versioning error 7 | #[derive(Debug, Fail)] 8 | pub enum Error { 9 | /// Hash sum can't be calculated because some files need to be 10 | /// generated during build 11 | #[fail(display="dependencies are not ready")] 12 | New, 13 | #[fail(display="{}", _0)] 14 | Fatal(FatalError), 15 | } 16 | 17 | impl Error { 18 | pub fn io>(e: io::Error, path: P) -> Error { 19 | return Error::Fatal(format_err!("{:?}: {}", path.as_ref(), e)); 20 | } 21 | } 22 | 23 | impl From for Error { 24 | fn from(e: FatalError) -> Error { 25 | Error::Fatal(e) 26 | } 27 | } 28 | 29 | #[cfg(feature="containers")] 30 | impl From<::git2::Error> for Error { 31 | fn from(e: ::git2::Error) -> Error { 32 | Error::Fatal(e.into()) 33 | } 34 | } 35 | 36 | #[cfg(feature="containers")] 37 | impl From> for Error { 38 | fn from(e: Vec<::path_filter::FilterError>) -> Error { 39 | // TODO(tailhook) improve display 40 | Error::Fatal(format_err!("{:?}", e)) 41 | } 42 | } 43 | 44 | impl From for Error { 45 | fn from(e: String) -> Error { 46 | Error::Fatal(err_msg(e)) 47 | } 48 | } 49 | 50 | impl From<&'static str> for Error { 51 | fn from(e: &'static str) -> Error { 52 | Error::Fatal(err_msg(e)) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/version/version.rs: -------------------------------------------------------------------------------- 1 | use crate::config::{Config, Container}; 2 | use crate::build_step::{BuildStep, Digest}; 3 | 4 | use super::error::Error; 5 | 6 | 7 | #[cfg(feature="containers")] 8 | fn all(container: &Container, cfg: &Config, debug_info: bool, dump: bool) 9 | -> Result 10 | { 11 | debug!("Versioning items: {}", container.setup.len()); 12 | 13 | let mut hash = Digest::new(debug_info, dump); 14 | 15 | hash.field("uids", &container.uids); 16 | hash.field("gids", &container.gids); 17 | 18 | for b in container.setup.iter() { 19 | debug!("Versioning setup: {:?}", b); 20 | hash.command(b.name()); 21 | b.hash(&cfg, &mut hash).map_err(|e| (format!("{:?}", b), e))?; 22 | } 23 | 24 | if !container.data_dirs.is_empty() { 25 | hash.field("data_dirs", &container.data_dirs); 26 | } 27 | if debug_info { 28 | hash.print_debug_info(); 29 | } 30 | if dump { 31 | hash.dump_info(); 32 | } 33 | 34 | Ok(format!("{:x}", hash)) 35 | } 36 | 37 | #[cfg(feature="containers")] 38 | pub fn short_version(container: &Container, cfg: &Config) 39 | -> Result 40 | { 41 | let hash_str = all(container, cfg, false, false)?; 42 | Ok(hash_str[..8].to_string()) 43 | } 44 | 45 | #[cfg(feature="containers")] 46 | pub fn long_version(container: &Container, cfg: &Config, 47 | debug_info: bool, dump: bool) 48 | -> Result 49 | { 50 | let hash_str = all(&container, cfg, debug_info, dump)?; 51 | Ok(hash_str) 52 | } 53 | -------------------------------------------------------------------------------- /src/wrapper/snapshot.rs: -------------------------------------------------------------------------------- 1 | use std::path::Path; 2 | use std::fs::symlink_metadata; 3 | use std::os::unix::fs::{MetadataExt, PermissionsExt}; 4 | 5 | use libmount::{BindMount, Tmpfs}; 6 | 7 | use crate::config::volumes::SnapshotInfo; 8 | use crate::container::mount::unmount; 9 | use crate::container::util::copy_dir; 10 | use crate::file_util::Dir; 11 | 12 | 13 | pub fn make_snapshot(src: &Path, dest: &Path, info: &SnapshotInfo) 14 | -> Result<(), String> 15 | { 16 | let tmp = Path::new("/tmp/mnt"); 17 | try_msg!(Dir::new(&tmp).recursive(true).create(), 18 | "Error creating temporary mountpoint: {err}"); 19 | let stat = try_msg!(symlink_metadata(&dest), 20 | "Error getting mountpoint metadata: {err}"); 21 | let mode = stat.permissions().mode(); 22 | let (uid, gid) = (stat.uid(), stat.gid()); 23 | BindMount::new(&src, &tmp).mount().map_err(|e| e.to_string())?; 24 | Tmpfs::new(&dest) 25 | .size_bytes(info.size) 26 | .mode(mode) 27 | .uid(uid) 28 | .gid(gid) 29 | .mount().map_err(|e| format!("{}", e))?; 30 | try_msg!(copy_dir(&tmp, dest, info.owner_uid, info.owner_gid), 31 | "Error copying directory: {err}"); 32 | unmount(tmp)?; 33 | Ok(()) 34 | } 35 | -------------------------------------------------------------------------------- /tests/alpine/vagga_inside_alpine/.gitignore: -------------------------------------------------------------------------------- 1 | vagga 2 | apk 3 | busybox 4 | alpine-keys.apk 5 | -------------------------------------------------------------------------------- /tests/alpine/vagga_inside_alpine/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | v33: 3 | setup: 4 | - !Alpine v3.3 5 | 6 | -------------------------------------------------------------------------------- /tests/badcmd.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/badcmd 3 | } 4 | 5 | @test "badcmd: Bad command help message" { 6 | run vagga bad-cmd 7 | [[ $status -eq 126 ]] 8 | [[ ${lines[${#lines[@]}-2]} =~ .*'Validation Error: Field run is expected'.* ]] 9 | [[ ${lines[${#lines[@]}-1]} =~ .*'Decode error at .commands.bad-cmd: missing field `run`'.* ]] 10 | } 11 | -------------------------------------------------------------------------------- /tests/badcmd/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | ubuntu: 3 | setup: [!Ubuntu trusty] 4 | 5 | commands: 6 | bad-cmd: !Command 7 | container: ubuntu 8 | -------------------------------------------------------------------------------- /tests/capsule.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/capsule 3 | } 4 | 5 | @test "capsule: Vagga in capsule runs" { 6 | run vagga vagga 7 | [[ $status = 127 ]] 8 | [[ $output = *"Recursive vagga"* ]] 9 | } 10 | 11 | @test "capsule: Vagga in capsule builds container" { 12 | run vagga vagga _capsule build v35-calc 13 | [[ $status = 0 ]] 14 | [[ $output = *"Container v35-calc (d6315e30) built"* ]] 15 | } 16 | 17 | @test "capsule: Vagga in capsule builds container and prints version" { 18 | run vagga vagga _capsule build --print-version v35-calc 19 | [[ $status = 0 ]] 20 | [[ ${lines[${#lines[@]}-1]} = "v35-calc.d6315e30" ]] 21 | } 22 | 23 | @test "capsule: Vagga in capsule runs command" { 24 | run vagga vagga _capsule run v35-calc bc < calc.txt 25 | [[ $status -eq 0 ]] 26 | [[ ${lines[${#lines[@]}-1]} = "2400" ]] 27 | } 28 | 29 | @test "capsule: Vagga can run local capsule script" { 30 | run vagga vagga _capsule script ./script.sh 33+27 31 | [[ $status -eq 0 ]] 32 | [[ ${lines[${#lines[@]}-1]} = "60" ]] 33 | } 34 | 35 | @test "capsule: Vagga can run remote capsule script" { 36 | scripturl="https://gist.githubusercontent.com/tailhook/0cf8adf45707c05702e5568b8d390ba9/raw/9f13527f7f94c27504b33f83e76da9514939b4c0/gistfile1.txt" 37 | run vagga vagga _capsule script "$scripturl" 33+27 38 | [[ $status -eq 0 ]] 39 | [[ ${lines[${#lines[@]}-1]} = "60" ]] 40 | } 41 | 42 | @test "capsule: Vagga capsule download" { 43 | scripturl="https://gist.githubusercontent.com/tailhook/0cf8adf45707c05702e5568b8d390ba9/raw/9f13527f7f94c27504b33f83e76da9514939b4c0/gistfile1.txt" 44 | run vagga vagga _capsule download "$scripturl" 45 | [[ $status -eq 0 ]] 46 | [[ ${lines[${#lines[@]}-1]} = "/vagga/cache/downloads/698319cf-gistfile1.txt" ]] 47 | } 48 | -------------------------------------------------------------------------------- /tests/capsule/calc.txt: -------------------------------------------------------------------------------- 1 | 100*24 2 | -------------------------------------------------------------------------------- /tests/capsule/script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | formula="$1" 3 | echo "$formula" | vagga _capsule run v35-calc bc 4 | -------------------------------------------------------------------------------- /tests/capsule/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | v35-calc: 3 | setup: 4 | - !Alpine v3.5 5 | - !Install [bc] 6 | 7 | commands: 8 | vagga: !CapsuleCommand 9 | description: Recursive vagga 10 | run: [vagga] 11 | 12 | sh: !CapsuleCommand 13 | description: Recursive vagga 14 | run: [sh] 15 | -------------------------------------------------------------------------------- /tests/completion/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | ubuntu: 3 | setup: 4 | - !Ubuntu trusty 5 | 6 | data: 7 | setup: 8 | - !Alpine v3.4 9 | data-dirs: [/var/lib] 10 | 11 | commands: 12 | yes: &yes !Command 13 | description: Run yes 14 | container: ubuntu 15 | run: yes 16 | 17 | no: &no !Command 18 | description: Run no 19 | container: ubuntu 20 | run: yes no 21 | 22 | dont_care: !Supervise 23 | description: Run 24 | children: 25 | yes: *yes 26 | no: *no 27 | -------------------------------------------------------------------------------- /tests/composer/Taskfile: -------------------------------------------------------------------------------- 1 | addTask('greet', function () { 7 | $this->getOutput()->writeln('Hello, Vagga!'); 8 | }); 9 | 10 | return $project; 11 | -------------------------------------------------------------------------------- /tests/composer/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mycompany/myproject", 3 | "require": { 4 | "task/task": "^0.6.0", 5 | "laravel/installer": "1.3.0" 6 | }, 7 | "require-dev": { 8 | "task/cli": "^0.3.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/composer_lock/Taskfile: -------------------------------------------------------------------------------- 1 | addTask('greet', function () { 7 | $this->getOutput()->writeln('Hello, Vagga!'); 8 | }); 9 | 10 | return $project; 11 | -------------------------------------------------------------------------------- /tests/composer_lock/composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mycompany/myproject", 3 | "require": { 4 | "task/task": "^0.6.0", 5 | "laravel/installer": "^1.3.0" 6 | }, 7 | "require-dev": { 8 | "task/cli": "^0.3.0" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /tests/composer_lock/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | # php 3 | php-composer-deps-lock: 4 | setup: 5 | - !Alpine v3.3 6 | - !ComposerDependencies 7 | -------------------------------------------------------------------------------- /tests/copy/dir/exe.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Hello!" 3 | -------------------------------------------------------------------------------- /tests/copy/dir/hello: -------------------------------------------------------------------------------- 1 | world 2 | -------------------------------------------------------------------------------- /tests/copy/dir/second: -------------------------------------------------------------------------------- 1 | file 2 | -------------------------------------------------------------------------------- /tests/copy/dir/subdir/file: -------------------------------------------------------------------------------- 1 | sub 2 | -------------------------------------------------------------------------------- /tests/copy/file: -------------------------------------------------------------------------------- 1 | data 2 | -------------------------------------------------------------------------------- /tests/cyclic.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/cyclic 3 | } 4 | 5 | @test "cyclic: Crash prevention" { 6 | run vagga crash-me-not 7 | [[ $status -eq 126 ]] 8 | [[ ${lines[${#lines[@]}-1]} = 'Container "crash" has cyclic dependency' ]] 9 | } 10 | -------------------------------------------------------------------------------- /tests/cyclic/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | crash: 4 | setup: 5 | - !Container crash 6 | - !Sh "echo hello" 7 | 8 | commands: 9 | 10 | crash-me-not: !Command 11 | container: crash 12 | run: "echo hello" 13 | -------------------------------------------------------------------------------- /tests/gem_bundler/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'cuba', '3.9.3' 4 | 5 | gem 'fpm', '1.14.1', group: :development 6 | -------------------------------------------------------------------------------- /tests/gem_bundler/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | pkg-alpine: 3 | setup: 4 | - !Alpine v3.4 5 | - !GemInstall [rake:11.1.1] 6 | 7 | pkg-alpine-no-update-gem: 8 | setup: 9 | - !Alpine v3.4 10 | - !GemConfig 11 | update_gem: false 12 | - !GemInstall [rake:11.1.1] 13 | 14 | pkg-ubuntu-focal: 15 | setup: 16 | - !Ubuntu focal 17 | - !GemInstall [fpm:1.14.1] 18 | 19 | pkg-ubuntu-focal-no-update-gem: 20 | setup: 21 | - !Ubuntu focal 22 | - !GemConfig 23 | update_gem: false 24 | - !GemInstall [fpm, "-v", 1.14.1] 25 | 26 | pkg-ubuntu-bionic: 27 | setup: 28 | - !Ubuntu bionic 29 | - !GemInstall [fpm:1.14.1] 30 | 31 | pkg-ubuntu-bionic-no-update-gem: 32 | setup: 33 | - !Ubuntu bionic 34 | - !GemConfig 35 | update_gem: false 36 | - !GemInstall [fpm, "-v", 1.14.1] 37 | 38 | bundle-alpine: 39 | setup: 40 | - !Alpine v3.4 41 | - !GemBundle 42 | 43 | bundle-alpine-no-dev: 44 | setup: 45 | - !Alpine v3.4 46 | - !GemBundle 47 | without: [development] 48 | 49 | bundle-ubuntu: 50 | setup: 51 | - !Ubuntu focal 52 | - !GemBundle 53 | 54 | bundle-ubuntu-no-dev: 55 | setup: 56 | - !Ubuntu focal 57 | - !GemBundle 58 | without: [development] 59 | 60 | bundle-invalid-trust-policy: 61 | setup: 62 | - !Alpine v3.4 63 | - !GemBundle 64 | trust_policy: invalid 65 | -------------------------------------------------------------------------------- /tests/gem_bundler_lock.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/gem_bundler_lock 3 | } 4 | 5 | teardown() { 6 | #if [ -d .bundle ]; then rm -r .bundle; fi 7 | return 0 8 | } 9 | 10 | @test "gem/bundler_lock: GemBundle lock" { 11 | run vagga _run bundle-lock rake --version 12 | [[ $status = 0 ]] 13 | [[ ${lines[${#lines[@]}-1]} = "rake, version 11.1.0" ]] 14 | link=$(readlink .vagga/bundle-lock) 15 | [[ $link = ".roots/bundle-lock.fe593b9a/root" ]] 16 | } 17 | -------------------------------------------------------------------------------- /tests/gem_bundler_lock/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'rake', '>= 11.1.0' -------------------------------------------------------------------------------- /tests/gem_bundler_lock/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | rake (11.1.0) 5 | 6 | PLATFORMS 7 | ruby 8 | 9 | DEPENDENCIES 10 | rake (>= 11.1.0) 11 | 12 | BUNDLED WITH 13 | 2.2.33 14 | -------------------------------------------------------------------------------- /tests/gem_bundler_lock/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | bundle-lock: 3 | setup: 4 | - !Alpine v3.4 5 | - !GemBundle 6 | -------------------------------------------------------------------------------- /tests/generic/.gitignore: -------------------------------------------------------------------------------- 1 | vagga-0.4.0.tar.xz 2 | test-file.zip 3 | tmp.tar.gz 4 | home/ 5 | -------------------------------------------------------------------------------- /tests/generic/environ.txt: -------------------------------------------------------------------------------- 1 | SHELL=/bin/sh 2 | -------------------------------------------------------------------------------- /tests/generic/etc/.gitignore: -------------------------------------------------------------------------------- 1 | hosts 2 | resolv.conf 3 | shakespeare 4 | -------------------------------------------------------------------------------- /tests/hardlinking/.gitignore: -------------------------------------------------------------------------------- 1 | /.storage 2 | -------------------------------------------------------------------------------- /tests/hardlinking/project-1/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | hello: 3 | setup: 4 | - !Text 5 | /etc/hello.txt: Hello world! 6 | 7 | hi: 8 | setup: 9 | - !Text 10 | /etc/hello.txt: Hi world! 11 | -------------------------------------------------------------------------------- /tests/hardlinking/project-2/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | hello-and-bye: 3 | setup: 4 | - !Text 5 | /etc/hello.txt: Hello world! 6 | /etc/bye.txt: Good bye! 7 | -------------------------------------------------------------------------------- /tests/hardlinking/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | hello: 3 | setup: 4 | - !Text 5 | /etc/hello.txt: Hello world! 6 | 7 | hello-and-bye: 8 | setup: 9 | - !Text 10 | /etc/hello.txt: Hello world! 11 | /etc/bye.txt: Good bye! 12 | -------------------------------------------------------------------------------- /tests/mixins.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/mixins 3 | } 4 | 5 | @test "mixins: Runs original command" { 6 | run vagga _build alpine 7 | run vagga top 8 | [[ $status = 0 ]] 9 | [[ $output = top ]] 10 | } 11 | 12 | @test "mixins: Overrides command" { 13 | run vagga _build alpine 14 | run vagga overrides 15 | [[ $status = 0 ]] 16 | [[ $output = overrides ]] 17 | } 18 | 19 | @test "mixins: Overrides in the middle" { 20 | run vagga _build alpine 21 | run vagga m1x 22 | [[ $status = 0 ]] 23 | [[ $output = m2 ]] 24 | } 25 | 26 | @test "mixins: Mixin command 1" { 27 | run vagga _build alpine 28 | run vagga m1 29 | [[ $status = 0 ]] 30 | [[ $output = m1 ]] 31 | } 32 | 33 | @test "mixins: Mixin command 2" { 34 | run vagga _build alpine 35 | run vagga m2 36 | [[ $status = 0 ]] 37 | [[ $output = m2 ]] 38 | } 39 | 40 | @test "mixins: List is correct" { 41 | run vagga _build alpine 42 | run vagga _list 43 | [[ $status = 0 ]] 44 | [[ "${lines[0]}" = "m1 " ]] 45 | [[ "${lines[1]}" = "m1x " ]] 46 | [[ "${lines[2]}" = "m2 " ]] 47 | [[ "${lines[3]}" = "overrides " ]] 48 | [[ "${lines[4]}" = "top " ]] 49 | } 50 | 51 | @test "mixins: Minimum version warning" { 52 | cd ../mixins_version 53 | run vagga _build test 54 | [[ $status = 0 ]] 55 | [[ $output != *"UnknownBuildStep"* ]] 56 | [[ $output = *"Please upgrade vagga"* ]] 57 | [[ $(echo $output |grep "Minimum Vagga Error" |wc -l) = 1 ]] 58 | } 59 | -------------------------------------------------------------------------------- /tests/mixins/mixins1.yaml: -------------------------------------------------------------------------------- 1 | commands: 2 | 3 | m1: !Command 4 | container: alpine 5 | run: [echo, m1] 6 | 7 | m1x: !Command 8 | container: alpine 9 | run: [echo, m1] 10 | 11 | overrides: !Command 12 | container: alpine 13 | run: [echo, m1] 14 | -------------------------------------------------------------------------------- /tests/mixins/mixins2.yaml: -------------------------------------------------------------------------------- 1 | commands: 2 | 3 | m1x: !Command 4 | container: alpine 5 | run: [echo, m2] 6 | 7 | m2: !Command 8 | container: alpine 9 | run: [echo, m2] 10 | -------------------------------------------------------------------------------- /tests/mixins/vagga.yaml: -------------------------------------------------------------------------------- 1 | mixins: 2 | - mixins1.yaml 3 | - mixins2.yaml 4 | 5 | containers: 6 | alpine: 7 | setup: 8 | - !Alpine v3.5 9 | 10 | commands: 11 | 12 | top: !Command 13 | container: alpine 14 | run: [echo, top] 15 | 16 | overrides: !Command 17 | container: alpine 18 | run: [echo, overrides] 19 | 20 | -------------------------------------------------------------------------------- /tests/mixins_version/mixins.yaml: -------------------------------------------------------------------------------- 1 | # Just tests error message, should be always bigger than real 2 | minimum-vagga: 9999.0.0 3 | 4 | containers: 5 | broken: 6 | setup: 7 | - !UnknownBuildStep 8 | -------------------------------------------------------------------------------- /tests/mixins_version/vagga.yaml: -------------------------------------------------------------------------------- 1 | mixins: 2 | - mixins.yaml 3 | 4 | containers: 5 | test: 6 | setup: [] 7 | -------------------------------------------------------------------------------- /tests/network.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/network 3 | vagga _build py 4 | } 5 | 6 | @test "network: bind port" { 7 | vagga bind & 8 | sleep 0.05 9 | run vagga connect 10 | kill %1 11 | [[ $status = 0 ]] 12 | [[ ${lines[0]} = "hello world!" ]] 13 | } 14 | 15 | @test "network: bind port in supervise" { 16 | vagga superbind & 17 | sleep 0.05 18 | run vagga connect 19 | kill %1 20 | [[ $status = 0 ]] 21 | [[ ${lines[0]} = "hello world!" ]] 22 | } 23 | -------------------------------------------------------------------------------- /tests/network/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | py: 3 | setup: 4 | - !Alpine v3.4 5 | - !Install [python3] 6 | 7 | commands: 8 | bind: &bind !Command 9 | container: py 10 | pass-tcp-socket: 31444 11 | run: 12 | - python3 13 | - -c 14 | - | 15 | import socket 16 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, fileno=3) 17 | while True: 18 | s, _ = sock.accept() 19 | a = s.recv(1024) 20 | s.send(a) 21 | 22 | connect: !Command 23 | container: py 24 | run: 25 | - python3 26 | - -c 27 | - | 28 | import socket 29 | sock = socket.create_connection(('127.0.0.1', 31444)) 30 | sock.send(b"hello world!") 31 | print(sock.recv(1024).decode('ascii', 'replace')) 32 | 33 | superbind: !Supervise 34 | children: 35 | bind: *bind 36 | -------------------------------------------------------------------------------- /tests/npm/.gitignore: -------------------------------------------------------------------------------- 1 | npm-debug.log 2 | -------------------------------------------------------------------------------- /tests/npm/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "something", 3 | "version": "1.0.0", 4 | "description": "", 5 | "dependencies": { 6 | "classnames": "2.2" 7 | }, 8 | "devDependencies": { 9 | "resolve-cli": "0.1" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tests/npm/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | pkg: 4 | setup: 5 | - !NpmInstall [resolve-cli] 6 | 7 | pkg-xenial: 8 | setup: 9 | - !Ubuntu xenial 10 | - !NpmInstall [resolve-cli] 11 | 12 | pkg-bionic: 13 | setup: 14 | - !Ubuntu bionic 15 | - !NpmInstall [resolve-cli] 16 | 17 | pkg-alpine: 18 | setup: 19 | - !Alpine v3.9 20 | - !NpmInstall [resolve-cli] 21 | 22 | git: 23 | setup: 24 | - !NpmInstall ["git+https://github.com/Witcher42/resolve-cli"] 25 | 26 | git-ubuntu: 27 | setup: 28 | - !Ubuntu trusty 29 | - !NpmInstall ["git+https://github.com/Witcher42/resolve-cli"] 30 | 31 | git-alpine: 32 | setup: 33 | - !Alpine v3.9 34 | - !NpmInstall ["git+https://github.com/Witcher42/resolve-cli"] 35 | 36 | npm-deps: 37 | setup: 38 | - !Alpine v3.9 39 | - !NpmDependencies { dev: false } 40 | 41 | npm-dev-deps: 42 | setup: 43 | - !Alpine v3.9 44 | - !NpmDependencies 45 | 46 | pkg-alpine-36: 47 | setup: 48 | - !Alpine v3.6 49 | - !NpmInstall [resolve-cli] 50 | 51 | -------------------------------------------------------------------------------- /tests/pip/.gitignore: -------------------------------------------------------------------------------- 1 | include-short.txt 2 | -------------------------------------------------------------------------------- /tests/pip/include-nested.txt: -------------------------------------------------------------------------------- 1 | --requirement include-short.txt 2 | -------------------------------------------------------------------------------- /tests/pip/req-https.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/tailhook/injections 2 | -------------------------------------------------------------------------------- /tests/pip/requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools 2 | urp 3 | -------------------------------------------------------------------------------- /tests/prerequisites.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/prerequisites 3 | vagga _build only 4 | } 5 | 6 | @test "prerequisites: One prerequisite" { 7 | run vagga two 8 | [[ $status = 0 ]] 9 | [[ ${lines[0]} = "one" ]] 10 | [[ ${lines[1]} = "two" ]] 11 | } 12 | 13 | @test "prerequisites: Collapsing prerequisites" { 14 | run vagga four 15 | [[ $status = 0 ]] 16 | [[ ${lines[0]} = "one" ]] 17 | [[ ${lines[1]} = "two" ]] 18 | [[ ${lines[2]} = "three" ]] 19 | [[ ${lines[3]} = "four" ]] 20 | } 21 | 22 | @test "prerequisites: Force order" { 23 | run vagga -m three two four 24 | [[ $status = 0 ]] 25 | [[ ${lines[0]} = "one" ]] 26 | [[ ${lines[1]} = "three" ]] 27 | [[ ${lines[2]} = "two" ]] 28 | [[ ${lines[3]} = "four" ]] 29 | } 30 | 31 | @test "prerequisites: Check persistent volume init" { 32 | run vagga persistent 33 | [[ $status = 0 ]] 34 | [[ ${lines[${#lines[@]}-1]} = "world" ]] 35 | } 36 | -------------------------------------------------------------------------------- /tests/prerequisites/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | only: 3 | setup: 4 | - !Alpine v3.4 5 | 6 | persistent: 7 | setup: 8 | - !Alpine v3.4 9 | volumes: 10 | /mnt: !Persistent 11 | init-command: _init-hello 12 | name: hello 13 | 14 | commands: 15 | one: !Command 16 | container: only 17 | run: [echo, one] 18 | 19 | two: !Command 20 | container: only 21 | prerequisites: [one] 22 | run: [echo, two] 23 | 24 | three: !Command 25 | container: only 26 | prerequisites: [one] 27 | run: [echo, three] 28 | 29 | four: !Command 30 | container: only 31 | prerequisites: [two, three] 32 | run: [echo, four] 33 | 34 | _init-hello: !Command 35 | container: persistent 36 | run: | 37 | echo world >> /mnt/hello.txt 38 | 39 | persistent: !Command 40 | container: persistent 41 | run: [cat, /mnt/hello.txt] 42 | -------------------------------------------------------------------------------- /tests/readonly.bats: -------------------------------------------------------------------------------- 1 | # Readonly tests run with vagga outside of vagrant 2 | 3 | @test "Vagga list works" { 4 | vagga _list 5 | } 6 | 7 | @test "Empty vagga has code 127" { 8 | run vagga 9 | [ "$status" -eq 127 ] 10 | } 11 | 12 | @test "Vagga build shell" { 13 | output=$(echo echo ok | vagga _build_shell) 14 | [ "$output" = "ok" ] 15 | } 16 | -------------------------------------------------------------------------------- /tests/subconfig.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/subconfig 3 | } 4 | 5 | @test "subconfig: Run bc" { 6 | run vagga calc 100*24 7 | [[ $status -eq 0 ]] 8 | [[ ${lines[${#lines[@]}-1]} = "2400" ]] 9 | link=$(readlink .vagga/subdir) 10 | [[ $link = ".roots/subdir.83b9845a/root" ]] 11 | } 12 | 13 | @test "subconfig: docker-raw" { 14 | run vagga _run docker-raw urp -Q key=val http://example.com 15 | [[ $status = 0 ]] 16 | [[ ${lines[${#lines[@]}-1]} = http://example.com?key=val ]] 17 | link=$(readlink .vagga/docker-raw) 18 | [[ $link = ".roots/docker-raw.7d5f876a/root" ]] 19 | } 20 | 21 | @test "subconfig: docker-smart" { 22 | run vagga _run docker-smart urp -Q key=val http://example.com 23 | [[ $status = 0 ]] 24 | [[ ${lines[${#lines[@]}-1]} = http://example.com?key=val ]] 25 | link=$(readlink .vagga/docker-smart) 26 | [[ $link = ".roots/docker-smart.fb95b4a3/root" ]] 27 | } 28 | -------------------------------------------------------------------------------- /tests/subconfig/.dockerignore: -------------------------------------------------------------------------------- 1 | .vagga 2 | -------------------------------------------------------------------------------- /tests/subconfig/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:focal 2 | RUN apt-get update 3 | RUN apt-get install -y \ 4 | # Comment line after continued line 5 | python pip 6 | # Some comment, just to ensure that it will be ignored 7 | RUN pip install setuptools urp 8 | -------------------------------------------------------------------------------- /tests/subconfig/docker-parser.yaml: -------------------------------------------------------------------------------- 1 | setup: 2 | - !Alpine v3.15 3 | - !Install [python3] 4 | - !Depends Dockerfile 5 | - !Depends docker2vagga.py 6 | - !Sh 'python3 ./docker2vagga.py > /vagga.yaml' 7 | -------------------------------------------------------------------------------- /tests/subconfig/subdir/docker-subconfigs.yaml: -------------------------------------------------------------------------------- 1 | docker-raw: 2 | setup: 3 | - !SubConfig 4 | source: !Container docker-parser 5 | path: vagga.yaml 6 | container: docker-raw 7 | 8 | docker-smart: 9 | setup: 10 | - !SubConfig 11 | source: !Container docker-parser 12 | path: vagga.yaml 13 | container: docker-smart 14 | -------------------------------------------------------------------------------- /tests/subconfig/subdir/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | calc: 4 | setup: 5 | - !Alpine v3.4 6 | - !Install [bc] 7 | -------------------------------------------------------------------------------- /tests/subconfig/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | docker-parser: !*Include docker-parser.yaml 4 | <<: [!*Include subdir/docker-subconfigs.yaml] 5 | 6 | subdir: 7 | setup: 8 | - !SubConfig 9 | path: subdir/vagga.yaml 10 | container: calc 11 | - !Sh "echo 2+3 | bc > /value.txt" 12 | 13 | commands: 14 | calc: !Command 15 | container: subdir 16 | accepts-arguments: true 17 | run: echo "$*" | bc 18 | -------------------------------------------------------------------------------- /tests/tty/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | python: 3 | setup: 4 | - !Alpine v3.4 5 | - !Install [python3] 6 | 7 | commands: 8 | python: &python !Command 9 | container: python 10 | run: [python3] 11 | 12 | counter: !Command 13 | container: python 14 | run: "python3 -c 'for i in range(1, 1000000): print(i)'" 15 | 16 | slow-counter: &slow-counter !Command 17 | container: python 18 | run: | 19 | python3 -c ' 20 | import time 21 | for i in range(1, 1000000): 22 | print(i) 23 | time.sleep(1)' 24 | 25 | stuck-counter: &stuck-counter !Command 26 | container: python 27 | run: | 28 | trap 'echo "SIGINT trapped"' 2 29 | trap 'echo "SIGTERM trapped"' 15 30 | for i in $(seq 1 1000000); do 31 | echo $i 32 | sleep 1 33 | sleep_st=$? 34 | if [ $sleep_st -ne 0 ] && [ $sleep_st -ne 130 ] && [ $sleep_st -ne 143 ]; then 35 | exit $sleep_st 36 | fi 37 | done 38 | 39 | run: !Supervise 40 | children: 41 | counter1: *slow-counter 42 | counter2: *slow-counter 43 | 44 | run-interactive: !Supervise 45 | children: 46 | python: *python 47 | counter: *slow-counter 48 | 49 | run-stuck: !Supervise 50 | kill-unresponsive-after: 10 51 | children: 52 | counter1: *slow-counter 53 | counter2: *stuck-counter 54 | 55 | run-interactive-stuck: !Supervise 56 | kill-unresponsive-after: 10 57 | children: 58 | python: *python 59 | counter: *stuck-counter 60 | -------------------------------------------------------------------------------- /tests/ubuntu_release/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | ubuntu-release: 4 | setup: 5 | - !UbuntuRelease { codename: impish } 6 | 7 | ubuntu-release-derive: 8 | setup: 9 | - !Container ubuntu-release 10 | - !Install [bc] 11 | 12 | trusty-calc: 13 | setup: 14 | - !UbuntuRelease { version: 14.04 } # backward-compat 15 | - !Install [bc] 16 | 17 | xenial-url: 18 | setup: 19 | - !UbuntuRelease 20 | url: http://cloud-images.ubuntu.com/xenial/current/xenial-server-cloudimg-amd64-root.tar.gz 21 | - !Install [bc] 22 | 23 | commands: 24 | echo-cmd: !Command 25 | container: ubuntu-release 26 | run: [echo] 27 | 28 | echo-shell: !Command 29 | container: ubuntu-release 30 | run: echo 31 | 32 | echo-shell-arg: !Command 33 | container: ubuntu-release 34 | accepts-arguments: true 35 | run: echo "$@" 36 | 37 | derived-calc: !Command 38 | container: ubuntu-release-derive 39 | accepts-arguments: true 40 | run: echo "$*" | bc 41 | 42 | trusty-calc: !Command 43 | container: trusty-calc 44 | accepts-arguments: true 45 | run: echo "$*" | bc 46 | 47 | xenial-calc: !Command 48 | container: xenial-url 49 | accepts-arguments: true 50 | run: echo "$*" | bc 51 | -------------------------------------------------------------------------------- /tests/uidmap.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/uidmap 3 | } 4 | 5 | @test "uidmap: Too much uids" { 6 | run vagga _build too-much-uids 7 | echo "Status: $status" 8 | [[ $status = 121 ]] 9 | [[ $output =~ "Number of allowed subuids is too small" ]] 10 | } 11 | 12 | @test "uidmap: Too much gids" { 13 | run vagga _build too-much-gids 14 | echo "Status: $status" 15 | [[ $status = 121 ]] 16 | [[ $output =~ "Number of allowed subgids is too small" ]] 17 | } 18 | 19 | @test "uidmap: Bad subuid" { 20 | echo user:0:65535 > /tmp/subuid 21 | echo root:x:0:0::/root:/bin/sh > /tmp/passwd 22 | echo user:!:1000:100::/home/user:/bin/sh >> /tmp/passwd 23 | mount --bind /tmp/passwd /etc/passwd 24 | mount --bind /tmp/subuid /etc/subuid 25 | run su user -c "vagga --ignore-owner-check _clean" 26 | umount /etc/subuid 27 | umount /etc/passwd 28 | echo "Status: $status" 29 | [[ $status = 121 ]] 30 | [[ $output =~ "includes original id" ]] 31 | } 32 | 33 | @test "uidmap: Bad subgid" { 34 | echo user:0:65536 > /tmp/subgid 35 | echo root:x:0:0::/root:/bin/sh > /tmp/passwd 36 | echo user:!:1000:100::/home/user:/bin/sh >> /tmp/passwd 37 | mount --bind /tmp/passwd /etc/passwd 38 | mount --bind /tmp/subgid /etc/subgid 39 | run su user -c "vagga --ignore-owner-check _build too-much-uids" 40 | umount /etc/subgid 41 | umount /etc/passwd 42 | echo "Status: $status" 43 | [[ $status = 121 ]] 44 | [[ $output =~ "includes original id" ]] 45 | } 46 | -------------------------------------------------------------------------------- /tests/uidmap/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | too-much-uids: 4 | uids: [0-1000000000] 5 | setup: 6 | - !Ubuntu trusty 7 | 8 | too-much-gids: 9 | gids: [0-1000000000] 10 | setup: 11 | - !Ubuntu trusty 12 | 13 | norm-uids: 14 | setup: 15 | - !Alpine v3.4 16 | -------------------------------------------------------------------------------- /tests/vcs/.gitignore: -------------------------------------------------------------------------------- 1 | /test.txt 2 | -------------------------------------------------------------------------------- /tests/vcs/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | git: 3 | setup: 4 | - !Alpine v3.4 5 | - !Install [python] 6 | - !Git 7 | url: https://github.com/jdp/urp.git 8 | path: /usr/share/urp 9 | 10 | git-install: 11 | setup: 12 | - !Alpine v3.4 13 | - !Install [python, py-setuptools] 14 | - !GitInstall 15 | url: https://github.com/jdp/urp.git 16 | script: python setup.py install 17 | 18 | git-describe: 19 | setup: 20 | - !GitDescribe /version.txt 21 | 22 | git-describe-no-file: 23 | setup: 24 | - !GitDescribe 25 | 26 | git-describe-pattern: 27 | setup: 28 | - !GitDescribe 29 | pattern: v* 30 | output-file: /version.txt 31 | 32 | 33 | commands: 34 | urp-git: !Command 35 | container: git 36 | environ: 37 | PYTHONPATH: /usr/share/urp 38 | run: [python, -m, urp] 39 | 40 | urp-git-install: !Command 41 | container: git-install 42 | run: [python, -m, urp] 43 | -------------------------------------------------------------------------------- /tests/version.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/version 3 | } 4 | 5 | @test "version: Check minimum version" { 6 | run vagga run something 7 | [[ $status = 126 ]] 8 | [[ ${lines[0]} = *'Minimum Vagga Error: Please upgrade vagga to at least "9999.0.0"' ]] 9 | [[ ${lines[1]} = *'Validation Error: The tag UnknownCommand is not expected' ]] 10 | } 11 | -------------------------------------------------------------------------------- /tests/version/vagga.yaml: -------------------------------------------------------------------------------- 1 | # Just tests error message, should be always bigger than real 2 | minimum-vagga: 9999.0.0 3 | 4 | containers: 5 | test: 6 | setup: 7 | - !UnknownCommand 8 | -------------------------------------------------------------------------------- /tests/volumes/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | # !CacheDir 4 | cachedir: 5 | setup: 6 | - !Alpine v3.5 7 | - !EnsureDir /mnt/cache 8 | - !EnsureDir /mnt/cache-root 9 | - !CacheDirs 10 | /mnt/cache: cachedir-volume-test 11 | - !Sh touch /mnt/cache/file.txt 12 | volumes: 13 | /mnt/cache: !CacheDir cachedir-volume-test 14 | 15 | cachedir-ubuntu: 16 | setup: 17 | - !Ubuntu xenial 18 | - !EnsureDir /mnt/cache 19 | - !CacheDirs 20 | /mnt/cache: cachedir-volume-test 21 | - !Sh touch /mnt/cache/file.txt 22 | volumes: 23 | /mnt/cache: !CacheDir cachedir-volume-test 24 | 25 | cachedir-add-files: 26 | setup: 27 | - !Alpine v3.5 28 | - !EnsureDir /mnt/cache 29 | volumes: 30 | /mnt/cache: !CacheDir cachedir-volume-test-add-files 31 | 32 | cachedir-mount-empty-path: 33 | setup: 34 | - !Alpine v3.5 35 | - !EnsureDir /mnt/cache 36 | volumes: 37 | /mnt/cache: !CacheDir "" 38 | 39 | cachedir-mount-absolute-path: 40 | setup: 41 | - !Alpine v3.5 42 | - !EnsureDir /mnt/cache 43 | volumes: 44 | /mnt/cache: !CacheDir /cache 45 | 46 | commands: 47 | 48 | # !CacheDir 49 | cachedir-count-files: !Command 50 | container: cachedir 51 | run: ls -1 /mnt/cache | wc -l 52 | 53 | cachedir-ubuntu-count-files: !Command 54 | container: cachedir-ubuntu 55 | run: ls -1 /mnt/cache | wc -l 56 | -------------------------------------------------------------------------------- /tests/yarn.bats: -------------------------------------------------------------------------------- 1 | setup() { 2 | cd /work/tests/yarn 3 | rm yarn.lock || true 4 | } 5 | 6 | @test "yarn: minimal" { 7 | cat < package.json 8 | { 9 | "devDependencies": { 10 | "resolve-cli": "0.1" 11 | } 12 | } 13 | END 14 | # don't check bin installations, because recent yarn have them broken 15 | run vagga resolve . 16 | [[ $status = 0 ]] 17 | [[ ${lines[${#lines[@]}-1]} = /work ]] 18 | run vagga _build pkg 19 | link=$(readlink .vagga/pkg) 20 | [[ $link = ".roots/pkg.dfb332bf/root" ]] 21 | 22 | run vagga stat /usr/lib/node_modules/classnames 23 | [[ $status = 1 ]] 24 | 25 | cat < package.json 26 | 27 | { 28 | "dependencies": { 29 | "classnames": "2.2" 30 | }, 31 | "devDependencies": { 32 | "resolve-cli": "0.1" 33 | } 34 | } 35 | END 36 | run vagga stat /usr/lib/node_modules/classnames 37 | [[ $status = 0 ]] 38 | [[ ${lines[${#lines[@]}-7]} = " File: /usr/lib/node_modules/classnames" ]] 39 | link=$(readlink .vagga/pkg) 40 | echo "Link: $link" 41 | [[ $link = ".roots/pkg.06364e8c/root" ]] 42 | run vagga resolve . 43 | [[ $status = 0 ]] 44 | [[ ${lines[${#lines[@]}-1]} = "/work" ]] 45 | } 46 | 47 | @test "yarn: specific yarn version" { 48 | cat < package.json 49 | 50 | { 51 | "dependencies": { 52 | "classnames": "2.2" 53 | }, 54 | "devDependencies": { 55 | "resolve-cli": "0.1" 56 | } 57 | } 58 | END 59 | run vagga version 60 | [[ $status = 0 ]] 61 | [[ ${lines[${#lines[@]}-1]} = "1.0.1" ]] 62 | link=$(readlink .vagga/version) 63 | echo "Link: $link" 64 | [[ $link = ".roots/version.0a8ecf27/root" ]] 65 | } 66 | -------------------------------------------------------------------------------- /tests/yarn/.gitignore: -------------------------------------------------------------------------------- 1 | /package.json 2 | /yarn.lock 3 | -------------------------------------------------------------------------------- /tests/yarn/vagga.yaml: -------------------------------------------------------------------------------- 1 | containers: 2 | 3 | pkg: 4 | setup: 5 | - !Alpine v3.5 6 | - !YarnDependencies 7 | 8 | version: 9 | setup: 10 | - !Alpine v3.6 11 | - !NpmConfig 12 | yarn-version: v1.0.1 13 | - !YarnDependencies 14 | 15 | 16 | commands: 17 | resolve: !Command 18 | container: pkg 19 | run: [resolve] 20 | environ: 21 | PATH: "/usr/lib/node_modules/.bin:\ 22 | /usr/local/sbin:/usr/local/bin:\ 23 | /usr/sbin:/usr/bin:/sbin:/bin" 24 | 25 | stat: !Command 26 | container: pkg 27 | run: [stat] 28 | 29 | version: !Command 30 | container: version 31 | run: [yarn, --version] 32 | --------------------------------------------------------------------------------