diff --git a/README.dev b/README.dev index 3aea867c6c..e8fb504ca3 100644 --- a/README.dev +++ b/README.dev @@ -1,6 +1,32 @@ Getting started =============== +Using Vagrant +------------- + +This is the recommended approach, but is only supported on Ubuntu 14.04. + + sudo apt-get install vagrant lxc lxc-templates cgroup-lite redir + vagrant plugin install vagrant-lxc + vagrant up --provider=lxc + vagrant ssh + # Now inside the container + sudo apt-get update + sudo apt-get install python-pbs + cd /srv/zulip && python provision.py + +To run the development server: + vagrant ssh -- -L9991:localhost:9991 + # Now inside the container + cd /srv/zulip + source /srv/zulip-venv/bin/activate + ./tools/run-dev.py + +You can now visit in your browser. + +By hand +------- + Install the following non-Python dependencies: * libffi-dev — needed for some Python extensions * postgresql 9.1 or later — our database (also install development headers) @@ -19,7 +45,11 @@ On Debian or Ubuntu systems: wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.1-tsearch-extras_0.1.2_amd64.deb sudo dpkg -i postgresql-9.1-tsearch-extras_0.1.2_amd64.deb - # If on 14.04, wait for us to support it. + # If on 14.04: + sudo apt-get install postgresql-9.3 + wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.3-tsearch-extras_0.1.2_amd64.deb + sudo dpkg -i postgresql-9.3-tsearch-extras_0.1.2_amd64.deb + # If on 15.04 or jessie: sudo apt-get install postgresql-9.4 wget https://dl.dropboxusercontent.com/u/283158365/zuliposs/postgresql-9.4-tsearch-extras_0.1_amd64.deb diff --git a/Vagrantfile b/Vagrantfile new file mode 100644 index 0000000000..0283d5aa46 --- /dev/null +++ b/Vagrantfile @@ -0,0 +1,118 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + # Every Vagrant virtual environment requires a box to build off of. + config.vm.box = "fgrehm/trusty64-lxc" + + # Disable automatic box update checking. If you disable this, then + # boxes will only be checked for updates when the user runs + # `vagrant box outdated`. This is not recommended. + # config.vm.box_check_update = false + + # Create a forwarded port mapping which allows access to a specific port + # within the machine from a port on the host machine. In the example below, + # accessing "localhost:8080" will access port 80 on the guest machine. + config.vm.network "forwarded_port", guest: 9991, host: 9991, host_ip: "127.0.0.1" + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # If true, then any SSH connections made will enable agent forwarding. + # Default value: false + # config.ssh.forward_agent = true + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + config.vm.synced_folder ".", "/vagrant", disabled: true + config.vm.synced_folder ".", "/srv/zulip" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + + config.vm.provider "virtualbox" do |vb| + override.vm.box = "ubuntu/trusty64" + end + # + # View the documentation for the provider you're using for more + # information on available options. + + # Enable provisioning with CFEngine. CFEngine Community packages are + # automatically installed. For example, configure the host as a + # policy server and optionally a policy file to run: + # + # config.vm.provision "cfengine" do |cf| + # cf.am_policy_hub = true + # # cf.run_file = "motd.cf" + # end + # + # You can also configure and bootstrap a client to an existing + # policy server: + # + # config.vm.provision "cfengine" do |cf| + # cf.policy_server_address = "10.0.2.15" + # end + + # Enable provisioning with Puppet stand alone. Puppet manifests + # are contained in a directory path relative to this Vagrantfile. + # You will need to create the manifests directory and a manifest in + # the file default.pp in the manifests_path directory. + # + # config.vm.provision "puppet" do |puppet| + # puppet.manifests_path = "manifests" + # puppet.manifest_file = "default.pp" + # end + + # Enable provisioning with chef solo, specifying a cookbooks path, roles + # path, and data_bags path (all relative to this Vagrantfile), and adding + # some recipes and/or roles. + # + # config.vm.provision "chef_solo" do |chef| + # chef.cookbooks_path = "../my-recipes/cookbooks" + # chef.roles_path = "../my-recipes/roles" + # chef.data_bags_path = "../my-recipes/data_bags" + # chef.add_recipe "mysql" + # chef.add_role "web" + # + # # You may also specify custom JSON attributes: + # chef.json = { mysql_password: "foo" } + # end + + # Enable provisioning with chef server, specifying the chef server URL, + # and the path to the validation key (relative to this Vagrantfile). + # + # The Opscode Platform uses HTTPS. Substitute your organization for + # ORGNAME in the URL and validation key. + # + # If you have your own Chef Server, use the appropriate URL, which may be + # HTTP instead of HTTPS depending on your configuration. Also change the + # validation key to validation.pem. + # + # config.vm.provision "chef_client" do |chef| + # chef.chef_server_url = "https://api.opscode.com/organizations/ORGNAME" + # chef.validation_key_path = "ORGNAME-validator.pem" + # end + # + # If you're using the Opscode platform, your validator client is + # ORGNAME-validator, replacing ORGNAME with your organization name. + # + # If you have your own Chef Server, the default validation client name is + # chef-validator, unless you changed the configuration. + # + # chef.validation_client_name = "ORGNAME-validator" +end diff --git a/provision.py b/provision.py new file mode 100644 index 0000000000..ba52a4fc67 --- /dev/null +++ b/provision.py @@ -0,0 +1,100 @@ +import os + +try: + import sh +except ImportError: + import pbs as sh + +APT_DEPENDENCIES = { + "trusty": [ + "libffi-dev", + "memcached", + "rabbitmq-server", + "libldap2-dev", + "redis-server", + "postgresql-server-dev-all", + "libmemcached-dev", + "postgresql-9.3", + "python-dev", + "hunspell-en-us", + "nodejs", + "python-virtualenv", + "git", + ] +} + +# tsearch-extras is an extension to postgres's built-in full-text search. +# TODO: use a real APT repository +TSEARCH_URL_BASE = "https://dl.dropboxusercontent.com/u/283158365/zuliposs/" +TSEARCH_PACKAGE_NAME = { + "trusty": "postgresql-9.3-tsearch-extras" +} +TSEARCH_VERSION = "0.1.2" +# TODO: this path is platform-specific! +TSEARCH_STOPWORDS_PATH = "/usr/share/postgresql/9.3/tsearch_data/" +REPO_STOPWORDS_PATH = os.path.join( + ZULIP_PATH, + "puppet", + "zulip", + "files", + "postgresql", + "zulip_english.stop", +) + +# TODO: support other architectures +ARCH = "amd64" + +VENV_PATH="/srv/zulip-venv" +ZULIP_PATH="/srv/zulip" + +with sh.sudo: + sh.apt_get.update() + + # TODO(lfaraone): add support for other distros + sh.apt_get.install("-y", *APT_DEPENDENCIES["trusty"]) + +temp_deb_path = sh.mktemp("--tmpdir", "package_XXXXXX.deb") + +sh.wget( + "{}/{}_{}_{}.deb".format( + TSEARCH_URL_BASE, + TSEARCH_PACKAGE_NAME["trusty"], + TSEARCH_VERSION, + ARCH, + ), + output_document=temp_deb_path, +) + +with sh.sudo: + sh.dpkg("--install", temp_deb_path) + +with sh.sudo: + sh.rm("-rf", VENV_PATH) + sh.mkdir("-p", VENV_PATH) + sh.chown("{}:{}".format(os.getuid(), os.getgid()), VENV_PATH) + +sh.virtualenv(VENV_PATH) + +orig_path = os.environ["PATH"] +os.environ["PATH"] = os.pathsep.join(( + os.path.join(ZULIP_PATH, "tools"), + os.path.join(ZULIP_PATH, "scripts", "setup"), + orig_path +)) + +activate_this = os.path.join(VENV_PATH, "bin", "activate_this.py") +execfile(activate_this, dict(__file__=activate_this)) + +sh.pip.install(r="requirements.txt") +with sh.sudo: + sh.cp(TSEARCH_STOPWORDS_PATH, REPO_STOPWORDS_PATH) + +os.chdir(ZULIP_PATH) + +import sys + +sh.configure_rabbitmq() +sh.postgres_init_db() +sh.do_destroy_rebuild_database() +sh.postgres_init_test_db() +sh.do_destroy_rebuild_test_database()