2
0
mirror of https://github.com/frappe/bench.git synced 2024-11-12 00:06:36 +00:00

chore: solve merge conflicts

* renme build_asset_files tp skip_asset
* add overwrite flag
* move building assets to postprocessing

Signed-off-by: Chinmay D. Pai <chinmaydpai@gmail.com>
This commit is contained in:
Chinmay D. Pai 2020-02-25 11:58:49 +05:30
commit 206d5ed3ae
No known key found for this signature in database
GPG Key ID: 75507BE256F40CED
50 changed files with 1369 additions and 912 deletions

47
.github/ISSUE_TEMPLATE/bug-report.md vendored Normal file
View File

@ -0,0 +1,47 @@
---
name: Bug report
about: Report a bug encountered while using bench
labels: bug
---
Issue: Bug report
**Do the checklist before filing an issue:**
- [ ] Can you replicate the issue?
- [ ] Is this something you can debug and fix? Send a pull request! Bug fixes and documentation fixes are welcome
**Describe the bug** :chart_with_downwards_trend:
A clear and concise description of what the bug is.
**To Reproduce** :page_with_curl:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior** :chart_with_upwards_trend:
A clear and concise description of what you expected to happen.
**Screenshots** :crystal_ball:
If applicable, add screenshots to help explain your problem.
**OS (please complete the following information):** :cyclone:
- [ ] Linux: `distro:version`
- [ ] macOS: `version`
- [ ] Windows `version`
- [ ] Others? `haros:distro:version`
**Version Information**
Can be found out by running `bench version` in your respective bench folder
- Bench Branch: `master` _(Only master is supported)_
- Frappe Version:
- ERPNext Version:
**Additional context** :page_facing_up:
Add any other context about the problem here.
**Possible Solution** :bookmark_tabs:
Any idea what might be causing the issue. Or if you have a proposed solution to the problem.

View File

@ -1,68 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
Issue: Bug report
Our project, as you've probably heard, is getting really popular and truth is we're getting a bit overwhelmed by the activity surrounding it. There are just too many issues for us to manage properly.
**Do the checklist before filing an issue:**
- [ ] Have a usage question? Ask your question on [Discuss Forum](https://discuss.erpnext.com). We use [Discuss Forum](https://discuss.erpnext.com) for usage question and GitHub for bugs.
- [ ] Can you replicate the issue?
- [ ] Is this something you can debug and fix? Send a pull request! Bug fixes and documentation fixes are welcome
**Describe the bug** :chart_with_downwards_trend:
A clear and concise description of what the bug is.
**To Reproduce** :page_with_curl:
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior** :chart_with_upwards_trend:
A clear and concise description of what you expected to happen.
**Screenshots** :crystal_ball:
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):** :cyclone:
- OS:
- [ ] Linux
- [ ] macOS
- [ ] Windows
- [ ] Others? Please mention:
- Browser:
- [ ] Safari
- [ ] Chrome
- [ ] Firefox
- [ ] Other? Please mention:
**Smartphone (please complete the following information):** :iphone: :computer:
- Device:
- [ ] iPhone
- [ ] Android
- Browser:
- [ ] Safari
- [ ] Chrome
- [ ] Firefox
- [ ] Other? Please mention:
**Version Information**
- Which branch are you on?
- [ ] `master` :star2:
- [ ] `develop` :fire:
- Frappe Version:
- ERPNext Version:
**Additional context** :page_facing_up:
Add any other context about the problem here.
**Possible Solution** :bookmark_tabs:
Any idea what might be causing the issue. Or if you have a proposed solution to the problem,
**Please don't be intimidated by the long list of options you've fill. Try to fill out as much as you can. Remember, the more the information the easier it is for us to replicate and fix the issue** :grin:

43
.github/ISSUE_TEMPLATE/easy-install.md vendored Normal file
View File

@ -0,0 +1,43 @@
---
name: Easy Install
about: Report a issue encountered or a suggestion for improving experience while using easy install to setup a "Bench + Frappe + ERPNext" environment
labels: easy-install
---
Issue: Easy Install
**Do the checklist before filing an issue:**
- [ ] Did you retain the logfile (path of logfile is shared while the script is run)? We definitely **need** the logfile to debug any easy install related issues.
- [ ] Is this something you can debug and fix? Send a pull request! Bug fixes and documentation fixes are welcome
**Distro Information (Required)**
<!--
Paste the contents of
1. uname -a
2. cat /etc/*-release
-->
**Command Run (Required)**
<!--
Knowing what was the exact command run ie which flags were used will help us narrow down the exact cause for the failure and put in a fix soon
-->
**Log File (Required)**
<!--
Upload the logfile and share the link for the same or just paste it directly (hopefully the last 50 lines should do)
-->
**Screenshots**
<!--
Optional: Screenshot of the runtime of the script
-->
**Additional context**
<!--
We need all the information we can get our hands on
-->
**Possible Solution**
<!--
Any idea what might be causing the issue. Or if you have a proposed solution to the problem?
-->

View File

@ -1,7 +1,7 @@
--- ---
name: Feature request name: Feature request
about: Suggest an idea for this project about: Suggest an idea for this project
label: feature-request
--- ---
Issue: Feature Request Issue: Feature Request

View File

@ -0,0 +1,19 @@
---
name: Question about using Bench/Frappe/Frappe Apps
about: This is not the appropriate channel
labels: invalid
---
Please post on our forums:
for questions about using `bench`, probably the best place to start is the [bench repo](https://github.com/frappe/bench) or [bench intro](https://frappe.io/bench) or [bench docs](https://frappe.io/docs/bench)
for questions about using the `Frappe Framework`: ~~https://discuss.frappe.io~~ => [stackoverflow](https://stackoverflow.com/questions/tagged/frappe) tagged under `frappe`
for questions about using `ERPNext`: https://discuss.erpnext.com
For documentation issues, use the [Frappe Framework Documentation](https://frappe.io/docs/user/en) or the [developer cheetsheet](https://github.com/frappe/frappe/wiki/Developer-Cheatsheet)
For a slightly outdated yet informative developer guide: https://www.youtube.com/playlist?list=PL3lFfCEoMxvzHtsZHFJ4T3n5yMM3nGJ1W
> **Posts that are not bug reports or feature requests will not be addressed on this issue tracker.**

View File

@ -1,4 +1,39 @@
Pull-Request <!--
Some key notes before you open a PR:
1. Select which branch should this PR be merged in?
2. PR name follows [convention](http://karma-runner.github.io/4.0/dev/git-commit-msg.html)
3. Update necessary Documentation
4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes
Also, if you're new here
- Documentation Guidelines => https://github.com/frappe/erpnext/wiki/Updating-Documentation
- Contribution Guide => https://github.com/frappe/bench/blob/master/docs/contribution_guidelines.md
- Pull Request Checklist => https://github.com/frappe/erpnext/wiki/Pull-Request-Checklist
-->
What type of a PR is this?
- [ ] Changes to Existing Features
- [ ] New Feature Submissions
- [ ] Bug Fix
- [ ] Breaking Change (include change in API behaviours, etc.)
---
> Please provide enough information so that others can review your pull request:
<!-- You can skip this if you're fixing a typo or updating existing documentation -->
---
> Explain the **details** for making this change. What existing problem does the pull request solve? The following checklist could help
- [ ] Have you followed the guidelines in our Contributing document? - [ ] Have you followed the guidelines in our Contributing document?
- [ ] Have you checked to ensure there aren't other open [Pull Requests](../pulls) for the same update/change? - [ ] Have you checked to ensure there aren't other open [Pull Requests](../pulls) for the same update/change?
@ -11,18 +46,8 @@ Pull-Request
--- ---
What type of a PR is this? <!-- Example: When "Adding a function to do X", explain why it is necessary to have a way to do X. -->
- [ ] Changes to Existing Features > Screenshots/GIFs
- [ ] New Feature Submissions
- [ ] Bug Fix
- [ ] Breaking Change
---
- Motivation and Context (What existing problem does the pull request solve):
- Related Issue:
- Screenshots (if applicable, remember, a picture tells a thousand words):
**Please don't be intimidated by the long list of options you've fill. Try to fill out as much as you can. Remember, the more the information the easier it is for us to test and get your pull request merged** :grin:
<!-- Add images/recordings to better visualize the change: expected/current behviour -->

246
README.md
View File

@ -1,222 +1,126 @@
<div align="center"> <div align="center">
<img src="https://github.com/frappe/design/raw/master/logos/png/bench-logo.png" height="128"> <img src="https://github.com/frappe/design/raw/master/logos/png/bench-logo.png" height="128">
<h2>Frappe Bench</h2> <h2>bench</h2>
</div> </div>
[![Build Status](https://circleci.com/gh/frappe/bench.svg?style=svg)](https://circleci.com/gh/frappe/bench) bench is a command-line utility that helps you to install apps, manage multiple sites and update Frappe / ERPNext apps on */nix (macOS, Ubuntu, Debian, CentOS, etc) for development and production.
The bench is a command-line utility that helps you to install apps, manage multiple sites and update Frappe / ERPNext apps on */nix (CentOS, Debian, Ubuntu, etc) for development and production. Bench will also create nginx and supervisor config files, setup backups and much more.
If you are using on a VPS make sure it has >= 1Gb of RAM or has swap setup properly. > **Note**: If you are looking for easier ways to get started and evaluate ERPNext, [download the Virtual Machine](https://erpnext.com/download) or take [a free trial on erpnext.com](https://erpnext.com/pricing).
To do this install, you must have basic information on how Linux works and should be able to use the command-line. If you are looking easier ways to get started and evaluate ERPNext, [download the Virtual Machine](https://erpnext.com/download) or take [a free trial on erpnext.com](https://erpnext.com/pricing). ---
If you have questions, please ask them on the [forum](https://discuss.erpnext.com/). # Table of Contents
## Installation - [bench CLI](#bench-cli)
- [Usage](#usage)
- [Installation](#installation)
- [Easy Install Script](#easy-install-script)
- [Release Bench](#release-bench)
- [Guides](#guides)
- [Resources](#resources)
- [License](#license)
---
### Installation Requirements # bench CLI
You will need a computer/server. Options include: Bench is a command line tool that helps you install, setup, manage multiple sites and apps based on Frappe Framework.
- A Normal Computer/VPS/Baremetal Server: This is strongly recommended. Frappe/ERPNext installs properly and works well on these ---
- A Raspberry Pi, SAN Appliance, Network Router, Gaming Console, etc.: Although you may be able to install Frappe/ERPNext on specialized hardware, it is unlikely to work well and will be difficult for us to support. Strongly consider using a normal computer/VPS/baremetal server instead. **We do not support specialized hardware**.
- A Toaster, Car, Firearm, Thermostat, etc.: Yes, many modern devices now have embedded computing capability. We live in interesting times. However, you should not install Frappe/ERPNext on these devices. Instead, install it on a normal computer/VPS/baremetal server. **We do not support installing on noncomputing devices**.
To install the Frappe/ERPNext server software, you will need an operating system on your normal computer which is not Windows. Note that the command line interface does work on Windows, and you can use Frappe/ERPNext from any operating system with a web browser. However, the server software does not run on Windows. It does run on other operating systems, so choose one of these instead: ## Usage
- Linux: Debian, Ubuntu, CentOS are the preferred distros and are well tested. [Arch Linux](https://github.com/frappe/bench/wiki/Install-ERPNext-on-ArchLinux) can also be used
- Mac OS X
### Manual Install
To manually install frappe/erpnext, you can follow this [this wiki](https://github.com/frappe/frappe/wiki/The-Hitchhiker%27s-Guide-to-Installing-Frappe-on-Linux) for Linux and [this wiki](https://github.com/frappe/frappe/wiki/The-Hitchhiker's-Guide-to-Installing-Frappe-on-Mac-OS-X) for MacOS. It gives an excellent explanation about the stack. You can also follow the steps mentioned below:
#### 1. Install Pre-requisites
<pre>
• Python 3.6+
• Node.js 12
• Redis 5 (caching and realtime updates)
• MariaDB 10.3 / Postgres 9.5 (to run database driven apps)
• yarn 1.12+ (js dependency manager)
• pip 15+ (py dependency manager)
• cron (scheduled jobs)
• wkhtmltopdf (version 0.12.5 with patched qt) (for pdf generation)
• Nginx (for production)
</pre>
#### 2. Install Bench
Install bench as a *non root* user,
git clone https://github.com/frappe/bench bench-repo
pip install --user -e bench-repo
Note: Please do not remove the bench directory the above commands will create
#### Basic Usage
* Create a new bench * Create a new bench
The init command will create a bench directory with frappe framework bench init [bench-name]
installed. It will be setup for periodic backups and auto updates once
a day.
bench init frappe-bench && cd frappe-bench * Add a site under current bench
* Add a site bench new-site [site-name]
Frappe apps are run by frappe sites and you will have to create at least one **Optional**: If the database for the site does not reside on localhost or listens on a custom port, you can use the flags `--db-host` to set a custom host and/or `--db-port` to set a custom port.
site. The new-site command allows you to do that.
bench new-site site1.local bench new-site [site-name] --db-host [custom-db-host-ip] --db-port [custom-db-port]
* Add apps * Add apps to bench
The get-app command gets remote frappe apps from a remote git repository and installs them. Example: [erpnext](https://github.com/frappe/erpnext) bench get-app [app-name] [app-link]
bench get-app erpnext https://github.com/frappe/erpnext * Install apps on a particular site
* Install apps bench --site [site-name] install-app [app-name]
To install an app on your new site, use the bench `install-app` command. * Start bench (only for development)
bench --site site1.local install-app erpnext
* Start bench
To start using the bench, use the `bench start` command
bench start bench start
To login to Frappe / ERPNext, open your browser and go to `[your-external-ip]:8000`, probably `localhost:8000` * Show bench help
The default username is "Administrator" and password is what you set when you created the new site. bench --help
_Note:_ Apart from `bench init`, all other bench commands have to be run having the respective bench directory as the working directory. _(`bench update` may also be run, but it's behaviour is covered in depth in the docs)_
For more in depth information on commands and usage follow [here](https://github.com/frappe/bench/blob/master/docs/commands_and_usage.md).
--- ---
## Easy Install ## Installation
To do this install, you must have basic information on how Linux works and should be able to use the command-line. bench will also create nginx and supervisor config files, setup backups and much more. If you are using on a VPS make sure it has >= 1Gb of RAM or has swap setup properly.
git clone https://github.com/frappe/bench ~/.bench
pip3 install --user -e ~/.bench
As bench is a python application, its installation really depends on `python` + `pip` + `git`. The Frappe Framework, however has various other system dependencies like `nodejs`, `yarn`, `redis` and a database system like `mariadb` or `postgres`. Go through the [installation requirements](https://github.com/frappe/bench/blob/master/docs/installation.md) for an updated list.
If you have questions, please ask them on the [forum](https://discuss.erpnext.com/c/bench) under the "Install / Update" category.
---
# Easy Install Script
- This is an opinionated setup so it is best to setup on a blank server. - This is an opinionated setup so it is best to setup on a blank server.
- Works on Ubuntu 16.04+, CentOS 7+, Debian 8+ - Works on Ubuntu 16.04+, CentOS 7+, Debian 8+
- You may have to install Python 2.7 (eg on Ubuntu 16.04+) by running `apt-get install python-minimal` - You may have to install Python 3 and other essentials by running `apt-get install python3-minimal build-essential python3-setuptools`
- You may also have to install build-essential and python-setuptools by running `apt-get install build-essential python-setuptools` - This script will install the pre-requisites, install bench and setup an ERPNext site `(site1.local under frappe-bench)`
- This script will install the pre-requisites, install bench and setup an ERPNext site - Passwords for Frappe Administrator and MariaDB (root) will be asked and saved under `~/passwoords.txt`
- Passwords for Frappe Administrator and MariaDB (root) will be asked
- MariaDB (root) password may be `password` on a fresh server - MariaDB (root) password may be `password` on a fresh server
- You can then login as **Administrator** with the Administrator password - You can then login as **Administrator** with the Administrator password
- If you find any problems, post them on the forum: [https://discuss.erpnext.com](https://discuss.erpnext.com) - The log file is saved under `/tmp/logs/install_bench.log` in case you run into any issues during the install.
- If you find any problems, post them on the forum: [https://discuss.erpnext.com](https://discuss.erpnext.com/c/bench) with the `installation_problem` under "Install / Update" category.
Open your Terminal and enter: wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
python3 install.py --production
#### 1. Download the install script Follow [Easy Install Docs](https://github.com/frappe/bench/blob/master/docs/easy_install.md) for more information.
For Linux:
wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
#### 2. Run the install script
If you are on a fresh server and logged in as root, at first create a dedicated user for frappe
& equip this user with sudo privileges
```
adduser [frappe-user]
usermod -aG sudo [frappe-user]
```
*(it is very common to use "frappe" as frappe-username, but this comes with the security flaw of ["frappe" ranking very high](https://www.reddit.com/r/dataisbeautiful/comments/b3sirt/i_deployed_over_a_dozen_cyber_honeypots_all_over/?st=JTJ0SC0Q&sh=76e05240) in as a username challenged in hacking attempts. So, for production sites it is highly recommended to use a custom username harder to guess)*
For developer setup:
sudo python install.py --develop
For production:
sudo python install.py --production --user [frappe-user]
use --user flag to create a user and install using that user (By default, the script will create a user with the username `frappe` if the --user flag is not used)
python install.py --develop --user [frappe-user]
use --container flag to install inside a container (this will prevent the `/proc/sys/vm/swappiness: Read-only` file system error)
sudo python install.py --production --user [frappe-user] --container
use --version flag to install specific version
python install.py --develop --version 11 --user [frappe-user]
use --python flag to specify virtual environments python version, by default script setup python 3
python install.py --develop --version 11 --python python2.7 --user [frappe-user]
#### What will this script do?
- Install all the pre-requisites
- Install the command line `bench`
- Create a new bench (a folder that will contain your entire frappe/erpnext setup)
- Create a new ERPNext site on the bench
#### How do I start ERPNext
1. For development: Go to your bench folder (`frappe-bench` by default) and start the bench with `bench start`
2. For production: Your process will be setup and managed by `nginx` and `supervisor`. [Setup Production](https://frappe.io/docs/user/en/bench/guides/setup-production.html)
--- ---
# Release Bench
## Bench Manager (GUI for Bench) Releases can be made for [Frappe](https://github.com/frappe/frappe) apps using bench. More information about this process can be found [here](https://github.com/frappe/bench/blob/master/docs/releasing_frappe_apps.md).
Bench Manager is a graphical user interface to emulate the functionalities of Frappé Bench. Like the command line utility it helps you install apps, manage multiple sites, update apps and much more. ---
### Installation # Bench Manager (GUI for Bench)
``` [Bench Manager](https://github.com/frappe/bench_manager) is a graphical user interface to emulate the functionalities of Frappe Bench. Like the command line utility it helps you install apps, manage multiple sites, update apps and much more. Install just by executing the following command in the respective bench directory.
$ bench setup manager
```
What all it does: bench setup manager
1. Create new site bench-manager.local
2. Gets the `bench_manager` app from https://github.com/frappe/bench_manager if it doesn't exist already
3. Installs the bench_manager app on the site bench-manager.local
## Docker Install - For Developers (beta) ---
1. For developer setup, you can also use the official [Frappé Docker](https://github.com/frappe/frappe_docker/). # Docker Install
2. The app, mariadb and redis run on individual containers
1. For developer setup, you can also use the official [Frappe Docker](https://github.com/frappe/frappe_docker/).
2. The app, mariadb and redis run on individual containers.
3. This setup supports multi-tenancy and exposes the frappe-bench volume as a external storage. 3. This setup supports multi-tenancy and exposes the frappe-bench volume as a external storage.
4. For more details, [read the instructions on the Frappé Docker README](https://github.com/frappe/frappe_docker/) 4. For more details, [ead the instructions on the [Frappe Docker README](https://github.com/frappe/frappe_docker/)
Help ---
====
For bench help, you can type # Guides
bench --help
Updating
========
To manually update the bench, run `bench update` to update all the apps, run
patches, build JS and CSS files and restart supervisor (if configured to).
You can also run the parts of the bench selectively.
`bench update --pull` will only pull changes in the apps
`bench update --patch` will only run database migrations in the apps
`bench update --build` will only build JS and CSS files for the bench
`bench update --bench` will only update the bench utility (this project)
`bench update --requirements` will only update dependencies (python packages) for the apps installed
Guides
=======
- [Configuring HTTPS](https://frappe.io/docs/user/en/bench/guides/configuring-https.html) - [Configuring HTTPS](https://frappe.io/docs/user/en/bench/guides/configuring-https.html)
- [Using Let's Encrypt to setup HTTPS](https://frappe.io/docs/user/en/bench/guides/lets-encrypt-ssl-setup.html) - [Using Let's Encrypt to setup HTTPS](https://frappe.io/docs/user/en/bench/guides/lets-encrypt-ssl-setup.html)
- [Diagnosing the Scheduler](https://frappe.io/docs/user/en/bench/guides/diagnosing-the-scheduler.html) - [Diagnosing the Scheduler](https://frappe.io/docs/user/en/bench/guides/diagnosing-the-scheduler.html)
@ -226,10 +130,16 @@ Guides
- [Setup Multitenancy](https://frappe.io/docs/user/en/bench/guides/setup-multitenancy.html) - [Setup Multitenancy](https://frappe.io/docs/user/en/bench/guides/setup-multitenancy.html)
- [Stopping Production](https://github.com/frappe/bench/wiki/Stopping-Production-and-starting-Development) - [Stopping Production](https://github.com/frappe/bench/wiki/Stopping-Production-and-starting-Development)
---
Resources # Resources
=======
- [Background Services](https://frappe.io/docs/user/en/bench/resources/background-services.html) - [Background Services](https://frappe.io/docs/user/en/bench/resources/background-services.html)
- [Bench Commands Cheat Sheet](https://frappe.io/docs/user/en/bench/resources/bench-commands-cheatsheet.html) - [Bench Commands Cheat Sheet](https://frappe.io/docs/user/en/bench/resources/bench-commands-cheatsheet.html)
- [Bench Procfile](https://frappe.io/docs/user/en/bench/resources/bench-procfile.html) - [Bench Procfile](https://frappe.io/docs/user/en/bench/resources/bench-procfile.html)
---
# License
bench is licensed under [GNU GPLv3](LICENSE)

View File

@ -94,7 +94,7 @@ def remove_from_excluded_apps_txt(app, bench_path='.'):
apps.remove(app) apps.remove(app)
return write_excluded_apps_txt(apps, bench_path=bench_path) return write_excluded_apps_txt(apps, bench_path=bench_path)
def get_app(git_url, branch=None, bench_path='.', build_asset_files=True, verbose=False, def get_app(git_url, branch=None, bench_path='.', skip_assets=False, verbose=False,
postprocess=True, overwrite=False): postprocess=True, overwrite=False):
# from bench.utils import check_url # from bench.utils import check_url
try: try:
@ -128,7 +128,7 @@ Do you want to continue and overwrite it?'''.format(repo_name)):
elif click.confirm('''Do you want to reinstall the existing application?''', abort=True): elif click.confirm('''Do you want to reinstall the existing application?''', abort=True):
app_name = get_app_name(bench_path, repo_name) app_name = get_app_name(bench_path, repo_name)
print("Reinstalling {0}".format(app_name)) print("Reinstalling {0}".format(app_name))
install_app(app=app_name, bench_path=bench_path, verbose=verbose, build_asset_files=build_asset_files) install_app(app=app_name, bench_path=bench_path, verbose=verbose, skip_assets=skip_assets)
sys.exit() sys.exit()
logger.info('Getting app {0}'.format(repo_name)) logger.info('Getting app {0}'.format(repo_name))
@ -140,7 +140,7 @@ Do you want to continue and overwrite it?'''.format(repo_name)):
app_name = get_app_name(bench_path, repo_name) app_name = get_app_name(bench_path, repo_name)
print("Installing {0}".format(app_name)) print("Installing {0}".format(app_name))
install_app(app=app_name, bench_path=bench_path, verbose=verbose, build_asset_files=build_asset_files) install_app(app=app_name, bench_path=bench_path, verbose=verbose, skip_assets=skip_assets)
def get_app_name(bench_path, repo_name): def get_app_name(bench_path, repo_name):
@ -169,7 +169,7 @@ def new_app(app, bench_path='.'):
install_app(app, bench_path=bench_path) install_app(app, bench_path=bench_path)
def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, build_asset_files=True): def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=True, skip_assets=False):
logger.info("installing {}".format(app)) logger.info("installing {}".format(app))
pip_path = os.path.join(bench_path, "env", "bin", "pip") pip_path = os.path.join(bench_path, "env", "bin", "pip")
@ -182,7 +182,7 @@ def install_app(app, bench_path=".", verbose=False, no_cache=False, postprocess=
add_to_appstxt(app, bench_path=bench_path) add_to_appstxt(app, bench_path=bench_path)
if postprocess: if postprocess:
if build_asset_files: if not skip_assets:
build_assets(bench_path=bench_path, app=app) build_assets(bench_path=bench_path, app=app)
conf = get_config(bench_path=bench_path) conf = get_config(bench_path=bench_path)
@ -427,7 +427,7 @@ def get_major_version(version):
def install_apps_from_path(path, bench_path='.'): def install_apps_from_path(path, bench_path='.'):
apps = get_apps_json(path) apps = get_apps_json(path)
for app in apps: for app in apps:
get_app(app['url'], branch=app.get('branch'), bench_path=bench_path, build_asset_files=False) get_app(app['url'], branch=app.get('branch'), bench_path=bench_path, skip_assets=True)
def get_apps_json(path): def get_apps_json(path):
if path.startswith('http'): if path.startswith('http'):
@ -438,12 +438,22 @@ def get_apps_json(path):
return json.load(f) return json.load(f)
def validate_branch(): def validate_branch():
for app in ['frappe', 'erpnext']: installed_apps = set(get_apps())
check_apps = set(['frappe', 'erpnext'])
intersection_apps = installed_apps.intersection(check_apps)
for app in intersection_apps:
branch = get_current_branch(app) branch = get_current_branch(app)
if branch == "master": if branch == "master":
print('''master branch is renamed to version-11 and develop to version-12. print("""'master' branch is renamed to 'version-11' since 'version-12' release.
Please switch to new branches to get future updates. As of January 2020, the following branches are
version Frappe ERPNext
11 version-11 version-11
12 version-12 version-12
13 develop develop
Please switch to new branches to get future updates.
To switch to your required branch, run the following commands: bench switch-to-branch [branch-name]""")
To switch to version 11, run the following commands: bench switch-to-branch version-11''')
sys.exit(1) sys.exit(1)

View File

@ -1,10 +1,11 @@
import click import click
import os, sys, logging, json, pwd, subprocess import os, sys, logging, json, pwd, subprocess
from bench.utils import is_root, PatchError, drop_privileges, get_env_cmd, get_cmd_output, get_frappe from bench.utils import is_root, PatchError, drop_privileges, get_env_cmd, get_cmd_output, get_frappe, log, is_bench_directory
from bench.app import get_apps from bench.app import get_apps
from bench.config.common_site_config import get_config from bench.config.common_site_config import get_config
from bench.commands import bench_command from bench.commands import bench_command
logger = logging.getLogger('bench') logger = logging.getLogger('bench')
from_command_line = False from_command_line = False
@ -12,6 +13,7 @@ def cli():
global from_command_line global from_command_line
from_command_line = True from_command_line = True
change_working_directory()
check_uid() check_uid()
change_dir() change_dir()
change_uid() change_uid()
@ -43,7 +45,7 @@ def cli():
def check_uid(): def check_uid():
if cmd_requires_root() and not is_root(): if cmd_requires_root() and not is_root():
print('superuser privileges required for this command') log('superuser privileges required for this command', level=3)
sys.exit(1) sys.exit(1)
def cmd_requires_root(): def cmd_requires_root():
@ -71,7 +73,7 @@ def change_uid():
drop_privileges(uid_name=frappe_user, gid_name=frappe_user) drop_privileges(uid_name=frappe_user, gid_name=frappe_user)
os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir os.environ['HOME'] = pwd.getpwnam(frappe_user).pw_dir
else: else:
print('You should not run this command as root') log('You should not run this command as root', level=3)
sys.exit(1) sys.exit(1)
def old_frappe_cli(bench_path='.'): def old_frappe_cli(bench_path='.'):
@ -93,6 +95,7 @@ def get_frappe_commands(bench_path='.'):
python = get_env_cmd('python', bench_path=bench_path) python = get_env_cmd('python', bench_path=bench_path)
sites_path = os.path.join(bench_path, 'sites') sites_path = os.path.join(bench_path, 'sites')
if not os.path.exists(sites_path): if not os.path.exists(sites_path):
log("Command not being executed in bench directory", level=3)
return [] return []
try: try:
output = get_cmd_output("{python} -m frappe.utils.bench_helper get-frappe-commands".format(python=python), cwd=sites_path) output = get_cmd_output("{python} -m frappe.utils.bench_helper get-frappe-commands".format(python=python), cwd=sites_path)
@ -113,3 +116,24 @@ def get_frappe_help(bench_path='.'):
return "Framework commands:\n" + out.split('Commands:')[1] return "Framework commands:\n" + out.split('Commands:')[1]
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
return "" return ""
def find_parent_bench(path):
"""Checks if parent directories are benches"""
if is_bench_directory(directory=path):
return path
home_path = os.path.expanduser("~")
root_path = os.path.abspath(os.sep)
if path not in {home_path, root_path}:
# NOTE: the os.path.split assumes that given path is absolute
parent_dir = os.path.split(path)[0]
return find_parent_bench(parent_dir)
def change_working_directory():
"""Allows bench commands to be run from anywhere inside a bench directory"""
cur_dir = os.path.abspath(".")
bench_path = find_parent_bench(cur_dir)
if bench_path:
os.chdir(bench_path)

View File

@ -1,15 +1,5 @@
import click import click
import os, shutil
import os.path as osp
import logging
from datetime import datetime
from bench.utils import which, exec_cmd
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
def print_bench_version(ctx, param, value): def print_bench_version(ctx, param, value):
"""Prints current bench version""" """Prints current bench version"""
@ -31,11 +21,14 @@ def bench_command(bench_path='.'):
setup_logging(bench_path=bench_path) setup_logging(bench_path=bench_path)
from bench.commands.make import init, get_app, new_app, remove_app from bench.commands.make import init, get_app, new_app, remove_app, exclude_app_for_update, include_app_for_update, pip
bench_command.add_command(init) bench_command.add_command(init)
bench_command.add_command(get_app) bench_command.add_command(get_app)
bench_command.add_command(new_app) bench_command.add_command(new_app)
bench_command.add_command(remove_app) bench_command.add_command(remove_app)
bench_command.add_command(exclude_app_for_update)
bench_command.add_command(include_app_for_update)
bench_command.add_command(pip)
from bench.commands.update import update, retry_upgrade, switch_to_branch, switch_to_master, switch_to_develop from bench.commands.update import update, retry_upgrade, switch_to_branch, switch_to_master, switch_to_develop
@ -45,9 +38,10 @@ bench_command.add_command(switch_to_branch)
bench_command.add_command(switch_to_master) bench_command.add_command(switch_to_master)
bench_command.add_command(switch_to_develop) bench_command.add_command(switch_to_develop)
from bench.commands.utils import (start, restart, set_nginx_port, set_ssl_certificate, set_ssl_certificate_key, set_url_root, from bench.commands.utils import (start, restart, set_nginx_port, set_ssl_certificate, set_ssl_certificate_key, set_url_root,
set_mariadb_host, set_default_site, download_translations, shell, backup_site, backup_all_sites, release, renew_lets_encrypt, set_mariadb_host, set_default_site, download_translations, shell, backup_site, backup_all_sites, release, renew_lets_encrypt,
disable_production, bench_src, prepare_beta_release, set_redis_cache_host, set_redis_queue_host, set_redis_socketio_host) disable_production, bench_src, prepare_beta_release, set_redis_cache_host, set_redis_queue_host, set_redis_socketio_host, find_benches, migrate_env)
bench_command.add_command(start) bench_command.add_command(start)
bench_command.add_command(restart) bench_command.add_command(restart)
bench_command.add_command(set_nginx_port) bench_command.add_command(set_nginx_port)
@ -68,6 +62,9 @@ bench_command.add_command(renew_lets_encrypt)
bench_command.add_command(disable_production) bench_command.add_command(disable_production)
bench_command.add_command(bench_src) bench_command.add_command(bench_src)
bench_command.add_command(prepare_beta_release) bench_command.add_command(prepare_beta_release)
bench_command.add_command(find_benches)
bench_command.add_command(migrate_env)
from bench.commands.setup import setup from bench.commands.setup import setup
bench_command.add_command(setup) bench_command.add_command(setup)
@ -83,108 +80,3 @@ bench_command.add_command(remote_urls)
from bench.commands.install import install from bench.commands.install import install
bench_command.add_command(install) bench_command.add_command(install)
from bench.config.common_site_config import get_config
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
@click.command('migrate-env')
@click.argument('python', type = str)
@click.option('--no-backup', is_flag=True)
def migrate_env(python, no_backup = False):
"""
Migrate Virtual Environment to desired Python Version.
"""
try:
# Clear Cache before Bench Dies.
config = get_config(bench_path = os.getcwd())
rredis = urlparse(config['redis_cache'])
redis = '{redis} -p {port}'.format(
redis = which('redis-cli'),
port = rredis.port
)
log.debug('Clearing Redis Cache...')
exec_cmd('{redis} FLUSHALL'.format(redis = redis))
log.debug('Clearing Redis DataBase...')
exec_cmd('{redis} FLUSHDB'.format(redis = redis))
except Exception:
log.warn('Please ensure Redis Connections are running or Daemonized.')
try:
# This is with the assumption that a bench is set-up within path.
path = os.getcwd()
# I know, bad name for a flag. Thanks, Ameya! :| - <achilles@frappe.io>
if not no_backup:
# Back, the f*ck up.
parch = osp.join(path, 'archived_envs')
if not osp.exists(parch):
os.mkdir(parch)
# Simply moving. Thanks, Ameya.
# I'm keen to zip.
source = osp.join(path, 'env')
target = parch
log.debug('Backing up Virtual Environment')
stamp = datetime.now().strftime('%Y%m%d_%H%M%S')
dest = osp.join(path, str(stamp))
# WARNING: This is an archive, you might have to use virtualenv --relocate
# That's because virtualenv creates symlinks with shebangs pointing to executables.
# shebangs, shebangs - ricky martin.
# ...and shutil.copytree is a f*cking mess.
os.rename(source, dest)
shutil.move(dest, target)
log.debug('Setting up a New Virtual {python} Environment'.format(
python = python
))
# Path to Python Executable (Basically $PYTHONPTH)
python = which(python)
virtualenv = which('virtualenv')
nvenv = 'env'
pvenv = osp.join(path, nvenv)
exec_cmd('{virtualenv} --python {python} {pvenv}'.format(
virtualenv = virtualenv,
python = python,
pvenv = pvenv
), cwd = path)
pip = osp.join(pvenv, 'bin', 'pip')
exec_cmd('{pip} install --upgrade pip'.format(pip=pip))
exec_cmd('{pip} install --upgrade setuptools'.format(pip=pip))
# TODO: Options
papps = osp.join(path, 'apps')
apps = ['frappe', 'erpnext'] + [app for app in os.listdir(papps) if app not in ['frappe', 'erpnext']]
for app in apps:
papp = osp.join(papps, app)
if osp.isdir(papp) and osp.exists(osp.join(papp, 'setup.py')):
exec_cmd('{pip} install -e {app}'.format(
pip = pip, app = papp
))
log.debug('Migration Successful to {python}'.format(
python = python
))
except:
log.debug('Migration Error')
raise
bench_command.add_command(migrate_env)
from bench.commands.make import exclude_app_for_update, include_app_for_update
bench_command.add_command(exclude_app_for_update)
bench_command.add_command(include_app_for_update)

View File

@ -14,7 +14,7 @@ def install_prerequisites():
@click.command('mariadb') @click.command('mariadb')
@click.option('--mysql_root_password') @click.option('--mysql_root_password')
@click.option('--version', default="10.2") @click.option('--version', default="10.3")
def install_maridb(mysql_root_password='', version=''): def install_maridb(mysql_root_password='', version=''):
if mysql_root_password: if mysql_root_password:
extra_vars.update({ extra_vars.update({

View File

@ -15,31 +15,53 @@ import click
@click.option('--skip-redis-config-generation', is_flag=True, help="Skip redis config generation if already specifying the common-site-config file") @click.option('--skip-redis-config-generation', is_flag=True, help="Skip redis config generation if already specifying the common-site-config file")
@click.option('--skip-assets',is_flag=True, default=False, help="Do not build assets") @click.option('--skip-assets',is_flag=True, default=False, help="Do not build assets")
@click.option('--verbose',is_flag=True, help="Verbose output during install") @click.option('--verbose',is_flag=True, help="Verbose output during install")
def init(path, apps_path, frappe_path, frappe_branch, no_procfile, no_backups, def init(path, apps_path, frappe_path, frappe_branch, no_procfile, no_backups, no_auto_update, clone_from, verbose, skip_redis_config_generation, clone_without_update, ignore_exist=False, skip_assets=False, python='python3'):
no_auto_update, clone_from, verbose, skip_redis_config_generation, clone_without_update,
ignore_exist = False, skip_assets=False,
python = 'python3'):
''' '''
Create a New Bench Instance. Create a New Bench Instance.
''' '''
from bench.utils import init from bench.utils import init, log
init(path, apps_path=apps_path, no_procfile=no_procfile, no_backups=no_backups,
no_auto_update=no_auto_update, frappe_path=frappe_path, frappe_branch=frappe_branch, try:
verbose=verbose, clone_from=clone_from, skip_redis_config_generation=skip_redis_config_generation, init(
path,
apps_path=apps_path,
no_procfile=no_procfile,
no_backups=no_backups,
no_auto_update=no_auto_update,
frappe_path=frappe_path,
frappe_branch=frappe_branch,
verbose=verbose,
clone_from=clone_from,
skip_redis_config_generation=skip_redis_config_generation,
clone_without_update=clone_without_update, clone_without_update=clone_without_update,
ignore_exist = ignore_exist, skip_assets=skip_assets, ignore_exist=ignore_exist,
python = python) skip_assets=skip_assets,
click.echo('Bench {} initialized'.format(path)) python=python,
)
log('Bench {} initialized'.format(path), level=1)
except SystemExit:
pass
except:
import os, shutil, time, six
# add a sleep here so that the traceback of other processes doesnt overlap with the prompts
time.sleep(1)
log("There was a problem while creating {}".format(path), level=2)
if six.moves.input("Do you want to rollback these changes? [Y/n]: ").lower() == "y":
print('Rolling back Bench "{}"'.format(path))
if os.path.exists(path):
shutil.rmtree(path)
@click.command('get-app') @click.command('get-app')
@click.argument('name', nargs=-1) # Dummy argument for backward compatibility @click.argument('name', nargs=-1) # Dummy argument for backward compatibility
@click.argument('git-url') @click.argument('git-url')
@click.option('--branch', default=None, help="branch to checkout") @click.option('--branch', default=None, help="branch to checkout")
@click.option('--overwrite', is_flag=True) @click.option('--overwrite', is_flag=True, default=False)
def get_app(git_url, branch, overwrite, name=None): @click.option('--skip-assets', is_flag=True, default=False, help="Do not build assets")
def get_app(git_url, branch, name=None, overwrite=False, skip_assets=False):
"clone an app from the internet and set it up in your bench" "clone an app from the internet and set it up in your bench"
from bench.app import get_app from bench.app import get_app
get_app(git_url, branch=branch, overwrite=overwrite) get_app(git_url, branch=branch, skip_assets=skip_assets, overwrite=overwrite)
@click.command('new-app') @click.command('new-app')
@ -72,3 +94,14 @@ def include_app_for_update(app_name):
"Include app from updating" "Include app from updating"
from bench.app import remove_from_excluded_apps_txt from bench.app import remove_from_excluded_apps_txt
remove_from_excluded_apps_txt(app_name) remove_from_excluded_apps_txt(app_name)
@click.command('pip', context_settings={"ignore_unknown_options": True}, help="For pip help use `bench pip help [COMMAND]` or `bench pip [COMMAND] -h`")
@click.argument('args', nargs=-1)
@click.pass_context
def pip(ctx, args):
"Run pip commands in bench env"
import os
from bench.utils import get_env_cmd
env_pip = get_env_cmd('pip')
os.execv(env_pip, (env_pip,) + args)

View File

@ -1,4 +1,5 @@
from bench.utils import exec_cmd from bench.utils import exec_cmd
from six import PY3
import click, sys, json import click, sys, json
import os import os
@ -57,7 +58,7 @@ def setup_production(user, yes=False):
# Install prereqs for production # Install prereqs for production
from distutils.spawn import find_executable from distutils.spawn import find_executable
if not find_executable('ansible'): if not find_executable('ansible'):
exec_cmd("sudo pip install ansible") exec_cmd("sudo {0} install ansible".format("pip3" if PY3 else "pip2"))
if not find_executable('fail2ban-client'): if not find_executable('fail2ban-client'):
exec_cmd("bench setup role fail2ban") exec_cmd("bench setup role fail2ban")
if not find_executable('nginx'): if not find_executable('nginx'):
@ -121,7 +122,7 @@ def set_ssh_port(port, force=False):
@click.command('lets-encrypt') @click.command('lets-encrypt')
@click.argument('site') @click.argument('site')
@click.option('--custom-domain') @click.option('--custom-domain')
@click.option('-n', '--non-interactive', default=False, is_flag=True, help="Run certbot non-interactively. Shouldn't be used on 1'st attempt") @click.option('-n', '--non-interactive', default=False, is_flag=True, help="Run command non-interactively. This flag restarts nginx and runs certbot non interactively. Shouldn't be used on 1'st attempt")
def setup_letsencrypt(site, custom_domain, non_interactive): def setup_letsencrypt(site, custom_domain, non_interactive):
"Setup lets-encrypt for site" "Setup lets-encrypt for site"
from bench.config.lets_encrypt import setup_letsencrypt from bench.config.lets_encrypt import setup_letsencrypt

View File

@ -5,9 +5,9 @@ from bench.config.common_site_config import get_config, update_config
from bench.app import pull_all_apps, is_version_upgrade, validate_branch from bench.app import pull_all_apps, is_version_upgrade, validate_branch
from bench.utils import (update_bench, validate_upgrade, pre_upgrade, post_upgrade, before_update, from bench.utils import (update_bench, validate_upgrade, pre_upgrade, post_upgrade, before_update,
update_requirements, update_node_packages, backup_all_sites, patch_sites, build_assets, update_requirements, update_node_packages, backup_all_sites, patch_sites, build_assets,
restart_supervisor_processes, restart_systemd_processes) restart_supervisor_processes, restart_systemd_processes, is_bench_directory)
from bench import patches from bench import patches
from six import reload_module from six.moves import reload_module
@click.command('update') @click.command('update')
@ -25,6 +25,11 @@ from six import reload_module
def update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, restart_systemd=False, requirements=False, no_backup=False, force=False, reset=False): def update(pull=False, patch=False, build=False, bench=False, auto=False, restart_supervisor=False, restart_systemd=False, requirements=False, no_backup=False, force=False, reset=False):
"Update bench" "Update bench"
if not is_bench_directory():
"""Update only bench if bench update called from outside a bench"""
update_bench(bench_repo=True, requirements=True)
sys.exit()
if not (pull or patch or build or bench or requirements): if not (pull or patch or build or bench or requirements):
pull, patch, build, bench, requirements = True, True, True, True, True pull, patch, build, bench, requirements = True, True, True, True, True
@ -35,7 +40,7 @@ def update(pull=False, patch=False, build=False, bench=False, auto=False, restar
conf = get_config(".") conf = get_config(".")
if bench and conf.get('update_bench_on_update'): if bench and conf.get('update_bench_on_update'):
update_bench() update_bench(bench_repo=True, requirements=False)
restart_update({ restart_update({
'pull': pull, 'pull': pull,
'patch': patch, 'patch': patch,

View File

@ -139,7 +139,7 @@ def shell(bench_path='.'):
def backup_site(site): def backup_site(site):
"backup site" "backup site"
from bench.utils import get_sites, backup_site from bench.utils import get_sites, backup_site
if not site in get_sites(bench_path='.'): if site not in get_sites(bench_path='.'):
print('site not found') print('site not found')
sys.exit(1) sys.exit(1)
backup_site(site, bench_path='.') backup_site(site, bench_path='.')
@ -190,3 +190,20 @@ def bench_src():
"""Prints bench source folder path, which can be used as: cd `bench src` """ """Prints bench source folder path, which can be used as: cd `bench src` """
import bench import bench
print(os.path.dirname(bench.__path__[0])) print(os.path.dirname(bench.__path__[0]))
@click.command('find')
@click.argument('location', default='')
def find_benches(location):
"""Finds benches recursively from location"""
from bench.utils import find_benches
find_benches(directory=location)
@click.command('migrate-env')
@click.argument('python', type=str)
@click.option('--no-backup', 'backup', is_flag=True, default=True)
def migrate_env(python, backup=True):
"""Migrate Virtual Environment to desired Python Version"""
from bench.utils import migrate_env
migrate_env(python=python, backup=backup)

View File

@ -29,9 +29,10 @@ def setup_letsencrypt(site, custom_domain, bench_path, interactive):
print("No custom domain named {0} set for site".format(custom_domain)) print("No custom domain named {0} set for site".format(custom_domain))
return return
click.confirm('Running this will stop the nginx service temporarily causing your sites to go offline\n' if interactive:
'Do you want to continue?', click.confirm('Running this will stop the nginx service temporarily causing your sites to go offline\n'
abort=True) 'Do you want to continue?',
abort=True)
if not get_config(bench_path).get("dns_multitenant"): if not get_config(bench_path).get("dns_multitenant"):
print("You cannot setup SSL without DNS Multitenancy") print("You cannot setup SSL without DNS Multitenancy")
@ -82,11 +83,10 @@ def run_certbot_and_setup_ssl(site, custom_domain, bench_path, interactive=True)
def setup_crontab(): def setup_crontab():
job_command = '/opt/certbot-auto renew -a nginx --post-hook "systemctl reload nginx"' job_command = '/opt/certbot-auto renew -a nginx --post-hook "systemctl reload nginx"'
system_crontab = CronTab(tabfile='/etc/crontab', user=True) system_crontab = CronTab(user='root')
if job_command not in str(system_crontab): if job_command not in str(system_crontab):
job = system_crontab.new(command=job_command, comment="Renew lets-encrypt every month") job = system_crontab.new(command=job_command, comment="Renew lets-encrypt every month")
job.every().month() job.day.on(1)
job.enable()
system_crontab.write() system_crontab.write()

View File

@ -12,7 +12,12 @@ map {{ from_variable }} {{ to_variable }} {
{%- macro server_block(bench_name, port, server_names, site_name, sites_path, ssl_certificate, ssl_certificate_key) %} {%- macro server_block(bench_name, port, server_names, site_name, sites_path, ssl_certificate, ssl_certificate_key) %}
server { server {
{% if ssl_certificate and ssl_certificate_key %}
listen {{ port }} ssl;
{% else %}
listen {{ port }}; listen {{ port }};
{% endif %}
server_name server_name
{% for name in server_names -%} {% for name in server_names -%}
{{ name }} {{ name }}
@ -30,12 +35,20 @@ server {
ssl_certificate {{ ssl_certificate }}; ssl_certificate {{ ssl_certificate }};
ssl_certificate_key {{ ssl_certificate_key }}; ssl_certificate_key {{ ssl_certificate_key }};
ssl_session_timeout 5m; ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2; ssl_session_cache shared:SSL:10m;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"; ssl_session_tickets off;
ssl_prefer_server_ciphers on; ssl_stapling on;
ssl_stapling_verify on;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
ssl_prefer_server_ciphers on;
{% endif %} {% endif %}
add_header X-Frame-Options "SAMEORIGIN"; add_header X-Frame-Options "SAMEORIGIN";
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
location /assets { location /assets {
try_files $uri =404; try_files $uri =404;

View File

@ -1,9 +1,14 @@
import os, sys, shutil, subprocess, logging, itertools, requests, json, platform, select, pwd, grp, multiprocessing, hashlib, glob import errno, glob, grp, itertools, json, logging, multiprocessing, os, platform, pwd, re, select, shutil, site, subprocess, sys
from datetime import datetime
from distutils.spawn import find_executable from distutils.spawn import find_executable
import bench
import requests
import semantic_version import semantic_version
from six import iteritems
from six.moves.urllib.parse import urlparse
import bench
from bench import env from bench import env
from six import iteritems, PY2
class PatchError(Exception): class PatchError(Exception):
@ -16,6 +21,38 @@ logger = logging.getLogger(__name__)
folders_in_bench = ('apps', 'sites', 'config', 'logs', 'config/pids') folders_in_bench = ('apps', 'sites', 'config', 'logs', 'config/pids')
class color:
nc = '\033[0m'
blue = '\033[94m'
green = '\033[92m'
yellow = '\033[93m'
red = '\033[91m'
def is_bench_directory(directory=os.path.curdir):
is_bench = True
for folder in folders_in_bench:
path = os.path.abspath(os.path.join(directory, folder))
is_bench = is_bench and os.path.exists(path)
return is_bench
def log(message, level=0):
levels = {
0: color.blue + 'LOG', # normal
1: color.green + 'SUCCESS', # success
2: color.red + 'ERROR', # fail
3: color.yellow + 'WARN' # warn/suggest
}
start = (levels.get(level) + ': ') if level in levels else ''
end = '\033[0m'
print(start + message + end)
def safe_decode(string, encoding = 'utf-8'): def safe_decode(string, encoding = 'utf-8'):
try: try:
string = string.decode(encoding) string = string.decode(encoding)
@ -33,36 +70,32 @@ def get_frappe(bench_path='.'):
def get_env_cmd(cmd, bench_path='.'): def get_env_cmd(cmd, bench_path='.'):
return os.path.abspath(os.path.join(bench_path, 'env', 'bin', cmd)) return os.path.abspath(os.path.join(bench_path, 'env', 'bin', cmd))
def init(path, apps_path=None, no_procfile=False, no_backups=False, def init(path, apps_path=None, no_procfile=False, no_backups=False, no_auto_update=False,
no_auto_update=False, frappe_path=None, frappe_branch=None, wheel_cache_dir=None, frappe_path=None, frappe_branch=None, wheel_cache_dir=None, verbose=False, clone_from=None,
verbose=False, clone_from=None, skip_redis_config_generation=False, skip_redis_config_generation=False, clone_without_update=False, ignore_exist = False, skip_assets=False, python='python3'):
clone_without_update=False, from bench.app import get_app, install_apps_from_path
ignore_exist = False, skip_assets=False, from bench.config import redis
python = 'python3'): # Let's change when we're ready. - <achilles@frappe.io> from bench.config.common_site_config import make_config
from .app import get_app, install_apps_from_path from bench.config.procfile import setup_procfile
from .config.common_site_config import make_config
from .config import redis
from .config.procfile import setup_procfile
from bench.patches import set_all_patches_executed from bench.patches import set_all_patches_executed
import os.path as osp if os.path.exists(path) and not ignore_exist:
log('Path {path} already exists!'.format(path=path))
if osp.exists(path): sys.exit(0)
if not ignore_exist: elif not os.path.exists(path):
raise ValueError('Bench Instance {path} already exists.'.format(path = path)) # only create dir if it does not exist
else:
os.makedirs(path) os.makedirs(path)
for dirname in folders_in_bench: for dirname in folders_in_bench:
try: try:
os.makedirs(os.path.join(path, dirname)) os.makedirs(os.path.join(path, dirname))
except OSError as e: except OSError as e:
if e.errno == os.errno.EEXIST: if e.errno == errno.EEXIST:
pass pass
setup_logging() setup_logging()
setup_env(bench_path=path, python = python) setup_env(bench_path=path, python=python)
make_config(path) make_config(path)
@ -72,7 +105,7 @@ def init(path, apps_path=None, no_procfile=False, no_backups=False,
if not frappe_path: if not frappe_path:
frappe_path = 'https://github.com/frappe/frappe.git' frappe_path = 'https://github.com/frappe/frappe.git'
get_app(frappe_path, branch=frappe_branch, bench_path=path, build_asset_files=False, verbose=verbose) get_app(frappe_path, branch=frappe_branch, bench_path=path, skip_assets=True, verbose=verbose)
if apps_path: if apps_path:
install_apps_from_path(apps_path, bench_path=path) install_apps_from_path(apps_path, bench_path=path)
@ -176,9 +209,7 @@ def setup_env(bench_path='.', python = 'python3'):
pip = os.path.join('env', 'bin', 'pip') pip = os.path.join('env', 'bin', 'pip')
exec_cmd('virtualenv -q {} -p {}'.format('env', python), cwd=bench_path) exec_cmd('virtualenv -q {} -p {}'.format('env', python), cwd=bench_path)
exec_cmd('{} -q install --upgrade pip'.format(pip), cwd=bench_path) exec_cmd('{} -q install -U pip wheel six'.format(pip), cwd=bench_path)
exec_cmd('{} -q install wheel'.format(pip), cwd=bench_path)
exec_cmd('{} -q install six'.format(pip), cwd=bench_path)
exec_cmd('{} -q install -e git+https://github.com/frappe/python-pdfkit.git#egg=pdfkit'.format(pip), cwd=bench_path) exec_cmd('{} -q install -e git+https://github.com/frappe/python-pdfkit.git#egg=pdfkit'.format(pip), cwd=bench_path)
def setup_socketio(bench_path='.'): def setup_socketio(bench_path='.'):
@ -208,14 +239,10 @@ def build_assets(bench_path='.', app=None):
exec_cmd(command, cwd=bench_path) exec_cmd(command, cwd=bench_path)
def get_sites(bench_path='.'): def get_sites(bench_path='.'):
sites_dir = os.path.join(bench_path, "sites") sites_path = os.path.join(bench_path, 'sites')
sites = [site for site in os.listdir(sites_dir) sites = (site for site in os.listdir(sites_path) if os.path.exists(os.path.join(sites_path, site, 'site_config.json')))
if os.path.isdir(os.path.join(sites_dir, site)) and site not in ('assets',)]
return sites return sites
def get_sites_dir(bench_path='.'):
return os.path.abspath(os.path.join(bench_path, 'sites'))
def get_bench_dir(bench_path='.'): def get_bench_dir(bench_path='.'):
return os.path.abspath(bench_path) return os.path.abspath(bench_path)
@ -256,13 +283,23 @@ def read_crontab():
s.stdout.close() s.stdout.close()
return out return out
def update_bench(): def update_bench(bench_repo=True, requirements=True):
logger.info('updating bench') logger.info("Updating bench")
# bench-repo folder # bench-repo folder
cwd = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) cwd = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
exec_cmd("git pull", cwd=cwd) if bench_repo:
try:
exec_cmd("git pull", cwd=cwd)
except bench.utils.CommandFailedError:
exec_cmd("git -c user.name=bench -c user.email=developers@frappe.io stash", cwd=cwd)
logger.info("Stashing changes made at {}\nUse git stash apply to recover changes after the successful update!".format(cwd))
if requirements:
update_bench_requirements()
logger.info("Bench Updated!")
def setup_sudoers(user): def setup_sudoers(user):
if not os.path.exists('/etc/sudoers.d'): if not os.path.exists('/etc/sudoers.d'):
@ -419,24 +456,28 @@ def restart_systemd_processes(bench_path='.', web_workers=False):
exec_cmd('sudo systemctl start -- $(systemctl show -p Requires {bench_name}.target | cut -d= -f2)'.format(bench_name=bench_name)) exec_cmd('sudo systemctl start -- $(systemctl show -p Requires {bench_name}.target | cut -d= -f2)'.format(bench_name=bench_name))
def set_default_site(site, bench_path='.'): def set_default_site(site, bench_path='.'):
if not site in get_sites(bench_path=bench_path): if site not in get_sites(bench_path=bench_path):
raise Exception("Site not in bench") raise Exception("Site not in bench")
exec_cmd("{frappe} --use {site}".format(frappe=get_frappe(bench_path=bench_path), site=site), exec_cmd("{frappe} --use {site}".format(frappe=get_frappe(bench_path=bench_path), site=site),
cwd=os.path.join(bench_path, 'sites')) cwd=os.path.join(bench_path, 'sites'))
def update_requirements(bench_path='.'): def update_bench_requirements():
print('Updating Python libraries...') bench_req_file = os.path.join(os.path.dirname(bench.__path__[0]), 'requirements.txt')
install_requirements(bench_req_file, user=True)
# update env pip def update_env_pip(bench_path):
env_pip = os.path.join(bench_path, 'env', 'bin', 'pip') env_pip = os.path.join(bench_path, 'env', 'bin', 'pip')
exec_cmd("{pip} install -q -U pip".format(pip=env_pip)) exec_cmd("{pip} install -q -U pip".format(pip=env_pip))
# Update bench requirements (at user level) def update_requirements(bench_path='.'):
bench_req_file = os.path.join(os.path.dirname(bench.__path__[0]), 'requirements.txt')
user_pip = which("pip" if PY2 else "pip3")
install_requirements(user_pip, bench_req_file, user=True)
from bench.app import get_apps, install_app from bench.app import get_apps, install_app
print('Updating Python libraries...')
# update env pip
update_env_pip(bench_path)
# Update bench requirements (at user level)
update_bench_requirements()
for app in get_apps(): for app in get_apps():
install_app(app, bench_path=bench_path) install_app(app, bench_path=bench_path)
@ -501,14 +542,19 @@ def update_npm_packages(bench_path='.'):
exec_cmd('npm install', cwd=bench_path) exec_cmd('npm install', cwd=bench_path)
def install_requirements(pip, req_file, user=False): def install_requirements(req_file, user=False):
if os.path.exists(req_file): if os.path.exists(req_file):
# sys.real_prefix exists only in a virtualenv if user:
if hasattr(sys, 'real_prefix'): python = sys.executable
else:
python = os.path.join("env", "bin", "python")
if in_virtual_env():
user = False user = False
user_flag = "--user" if user else "" user_flag = "--user" if user else ""
exec_cmd("{pip} install {user_flag} -q -U -r {req_file}".format(pip=pip, user_flag=user_flag, req_file=req_file))
exec_cmd("{python} -m pip install {user_flag} -q -U -r {req_file}".format(python=python, user_flag=user_flag, req_file=req_file))
def backup_site(site, bench_path='.'): def backup_site(site, bench_path='.'):
bench.set_frappe_version(bench_path=bench_path) bench.set_frappe_version(bench_path=bench_path)
@ -678,11 +724,13 @@ def post_upgrade(from_ver, to_ver, bench_path='.'):
if from_ver <= 5 and to_ver == 6: if from_ver <= 5 and to_ver == 6:
setup_socketio(bench_path=bench_path) setup_socketio(bench_path=bench_path)
print("As you have setup your bench for production, you will have to reload configuration for nginx and supervisor") message = """
print("To complete the migration, please run the following commands") As you have setup your bench for production, you will have to reload configuration for nginx and supervisor. To complete the migration, please run the following commands
print() sudo service nginx restart
print("sudo service nginx restart") sudo supervisorctl reload
print("sudo supervisorctl reload") """.strip()
print(message)
def update_translations_p(args): def update_translations_p(args):
try: try:
@ -690,6 +738,7 @@ def update_translations_p(args):
except requests.exceptions.HTTPError: except requests.exceptions.HTTPError:
print('Download failed for', args[0], args[1]) print('Download failed for', args[0], args[1])
def download_translations_p(): def download_translations_p():
pool = multiprocessing.Pool(4) pool = multiprocessing.Pool(4)
@ -699,18 +748,21 @@ def download_translations_p():
pool.map(update_translations_p, args) pool.map(update_translations_p, args)
def download_translations(): def download_translations():
langs = get_langs() langs = get_langs()
apps = ('frappe', 'erpnext') apps = ('frappe', 'erpnext')
for app, lang in itertools.product(apps, langs): for app, lang in itertools.product(apps, langs):
update_translations(app, lang) update_translations(app, lang)
def get_langs(): def get_langs():
lang_file = 'apps/frappe/frappe/geo/languages.json' lang_file = 'apps/frappe/frappe/geo/languages.json'
with open(lang_file) as f: with open(lang_file) as f:
langs = json.loads(f.read()) langs = json.loads(f.read())
return [d['code'] for d in langs] return [d['code'] for d in langs]
def update_translations(app, lang): def update_translations(app, lang):
translations_dir = os.path.join('apps', app, app, 'translations') translations_dir = os.path.join('apps', app, app, 'translations')
csv_file = os.path.join(translations_dir, lang + '.csv') csv_file = os.path.join(translations_dir, lang + '.csv')
@ -755,15 +807,18 @@ def log_line(data, stream):
return sys.stderr.write(data) return sys.stderr.write(data)
return sys.stdout.write(data) return sys.stdout.write(data)
def get_output(*cmd): def get_output(*cmd):
s = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) s = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out = s.stdout.read() out = s.stdout.read()
s.stdout.close() s.stdout.close()
return out return out
def before_update(bench_path, requirements): def before_update(bench_path, requirements):
validate_pillow_dependencies(bench_path, requirements) validate_pillow_dependencies(bench_path, requirements)
def validate_pillow_dependencies(bench_path, requirements): def validate_pillow_dependencies(bench_path, requirements):
if not requirements: if not requirements:
return return
@ -791,9 +846,11 @@ def validate_pillow_dependencies(bench_path, requirements):
raise raise
def get_bench_name(bench_path): def get_bench_name(bench_path):
return os.path.basename(os.path.abspath(bench_path)) return os.path.basename(os.path.abspath(bench_path))
def setup_fonts(): def setup_fonts():
fonts_path = os.path.join('/tmp', 'fonts') fonts_path = os.path.join('/tmp', 'fonts')
@ -808,6 +865,7 @@ def setup_fonts():
shutil.rmtree(fonts_path) shutil.rmtree(fonts_path)
exec_cmd("fc-cache -fv") exec_cmd("fc-cache -fv")
def set_git_remote_url(git_url, bench_path='.'): def set_git_remote_url(git_url, bench_path='.'):
"Set app remote git url" "Set app remote git url"
app = git_url.rsplit('/', 1)[1].rsplit('.', 1)[0] app = git_url.rsplit('/', 1)[1].rsplit('.', 1)[0]
@ -820,6 +878,7 @@ def set_git_remote_url(git_url, bench_path='.'):
if os.path.exists(os.path.join(app_dir, '.git')): if os.path.exists(os.path.join(app_dir, '.git')):
exec_cmd("git remote set-url upstream {}".format(git_url), cwd=app_dir) exec_cmd("git remote set-url upstream {}".format(git_url), cwd=app_dir)
def run_playbook(playbook_name, extra_vars=None, tag=None): def run_playbook(playbook_name, extra_vars=None, tag=None):
if not find_executable('ansible'): if not find_executable('ansible'):
print("Ansible is needed to run this command, please install it using 'pip install ansible'") print("Ansible is needed to run this command, please install it using 'pip install ansible'")
@ -833,3 +892,154 @@ def run_playbook(playbook_name, extra_vars=None, tag=None):
args.extend(['-t', tag]) args.extend(['-t', tag])
subprocess.check_call(args, cwd=os.path.join(os.path.dirname(bench.__path__[0]), 'playbooks')) subprocess.check_call(args, cwd=os.path.join(os.path.dirname(bench.__path__[0]), 'playbooks'))
def find_benches(directory=None):
if not directory:
directory = os.path.expanduser("~")
elif os.path.exists(directory):
directory = os.path.abspath(directory)
else:
log("Directory doesn't exist", level=2)
sys.exit(1)
if is_bench_directory(directory):
if os.path.curdir == directory:
print("You are in a bench directory!")
else:
print("{0} is a bench directory!".format(directory))
return
benches = []
for sub in os.listdir(directory):
sub = os.path.join(directory, sub)
if os.path.isdir(sub) and not os.path.islink(sub):
if is_bench_directory(sub):
print("{} found!".format(sub))
benches.append(sub)
else:
benches.extend(find_benches(sub))
return benches
def in_virtual_env():
# type: () -> bool
"""Returns a boolean, whether running in venv with no system site-packages.
pip really does the best job at this: virtualenv_no_global at https://raw.githubusercontent.com/pypa/pip/master/src/pip/_internal/utils/virtualenv.py
"""
def running_under_venv():
# handles PEP 405 compliant virtual environments.
return sys.prefix != getattr(sys, "base_prefix", sys.prefix)
def running_under_regular_virtualenv():
# pypa/virtualenv case
return hasattr(sys, 'real_prefix')
def _no_global_under_venv():
# type: () -> bool
"""Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion
PEP 405 specifies that when system site-packages are not supposed to be
visible from a virtual environment, `pyvenv.cfg` must contain the following
line:
include-system-site-packages = false
Additionally, log a warning if accessing the file fails.
"""
def _get_pyvenv_cfg_lines():
pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg')
try:
with open(pyvenv_cfg_file) as f:
return f.read().splitlines() # avoids trailing newlines
except IOError:
return None
_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile(
r"include-system-site-packages\s*=\s*(?P<value>true|false)"
)
cfg_lines = _get_pyvenv_cfg_lines()
if cfg_lines is None:
# We're not in a "sane" venv, so assume there is no system
# site-packages access (since that's PEP 405's default state).
return True
for line in cfg_lines:
match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line)
if match is not None and match.group('value') == 'false':
return True
return False
def _no_global_under_regular_virtualenv():
# type: () -> bool
"""Check if "no-global-site-packages.txt" exists beside site.py
This mirrors logic in pypa/virtualenv for determining whether system
site-packages are visible in the virtual environment.
"""
site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
no_global_site_packages_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt')
return os.path.exists(no_global_site_packages_file)
if running_under_regular_virtualenv():
return _no_global_under_regular_virtualenv()
if running_under_venv():
return _no_global_under_venv()
return False
def migrate_env(python, backup=False):
from bench.config.common_site_config import get_config
from bench.app import get_apps
log = logging.getLogger(__name__)
log.setLevel(logging.DEBUG)
nvenv = 'env'
path = os.getcwd()
python = which(python)
virtualenv = which('virtualenv')
pvenv = os.path.join(path, nvenv)
pip = os.path.join(pvenv, 'bin', 'pip')
# Clear Cache before Bench Dies.
try:
config = get_config(bench_path=os.getcwd())
rredis = urlparse(config['redis_cache'])
redis = '{redis} -p {port}'.format(redis=which('redis-cli'), port=rredis.port)
log.debug('Clearing Redis Cache...')
exec_cmd('{redis} FLUSHALL'.format(redis = redis))
log.debug('Clearing Redis DataBase...')
exec_cmd('{redis} FLUSHDB'.format(redis = redis))
except:
log.warn('Please ensure Redis Connections are running or Daemonized.')
# Backup venv: restore using `virtualenv --relocatable` if needed
if backup:
parch = os.path.join(path, 'archived_envs')
if not os.path.exists(parch):
os.mkdir(parch)
source = os.path.join(path, 'env')
target = parch
log.debug('Backing up Virtual Environment')
stamp = datetime.now().strftime('%Y%m%d_%H%M%S')
dest = os.path.join(path, str(stamp))
os.rename(source, dest)
shutil.move(dest, target)
# Create virtualenv using specified python
try:
log.debug('Setting up a New Virtual {} Environment'.format(python))
exec_cmd('{virtualenv} --python {python} {pvenv}'.format(virtualenv=virtualenv, python=python, pvenv=pvenv))
apps = ' '.join(["-e {}".format(os.path.join("apps", app)) for app in get_apps()])
exec_cmd('{0} install -q -U {1}'.format(pip, apps))
log.debug('Migration Successful to {}'.format(python))
except:
log.debug('Migration Error')
raise

View File

@ -0,0 +1,69 @@
## Usage
* Updating
Currently, `bench update` can be run from any directory however the context of the command changes. If run from a bench directory, the vanilla command itself updates all apps, runs migrations and backs up all sites.
bench update
To manually update the bench, run `bench update` to update all the apps, run
patches, build JS and CSS files and restart supervisor (if configured to).
You can also run the parts of the bench selectively.
`bench update --pull` will only pull changes in the apps
`bench update --patch` will only run database migrations in the apps
`bench update --build` will only build JS and CSS files for the bench
`bench update --bench` will only update the bench utility (this project)
`bench update --requirements` will only update all dependencies (Python + Node) for the apps available in current bench
* Create a new bench
The init command will create a bench directory with frappe framework installed. It will be setup for periodic backups and auto updates once a day.
bench init frappe-bench && cd frappe-bench
* Add a site
Frappe apps are run by frappe sites and you will have to create at least one site. The new-site command allows you to do that.
bench new-site site1.local
* Add apps
The get-app command gets remote frappe apps from a remote git repository and installs them. Example: [erpnext](https://github.com/frappe/erpnext)
bench get-app erpnext https://github.com/frappe/erpnext
* Install apps
To install an app on your new site, use the bench `install-app` command.
bench --site site1.local install-app erpnext
* Start bench
To start using the bench, use the `bench start` command
bench start
To login to Frappe / ERPNext, open your browser and go to `[your-external-ip]:8000`, probably `localhost:8000`
The default username is "Administrator" and password is what you set when you created the new site.
* Setup Manager
## What it does
bench setup manager
1. Create new site bench-manager.local
2. Gets the `bench_manager` app from https://github.com/frappe/bench_manager if it doesn't exist already
3. Installs the bench_manager app on the site bench-manager.local

View File

@ -2,9 +2,9 @@
### Introduction (for first timers) ### Introduction (for first timers)
Thank you for your interesting in contributing to an open source project! Our world works on people taking initiative to contribute to the "commons" and contributing to open source means you are contributing to make things better for not only yourself, but everyone else too! So thank you for taking this initiative. Thank you for your interest in contributing to our project! Our world works on people taking initiative to contribute to the "commons" and contributing to open source means you are contributing to make things better for not only yourself, but everyone else too! So kudos to you for taking this initiative.
Great projects also work because of great quality. Open source or not, the user really cares that things should work as they are advertised, and consistently. New features should follow the same pattern and so that users don't have to learn things again and again. Great projects depend on good code quality and adhering to certain standards while making sure the goals of the project are met. New features should follow the same pattern and so that users don't have to learn things again and again.
Developers who maintain open source also expect that you follow certain guidelines. These guidelines ensure that developers are able quickly give feedback on your contribution and how to make it better. Most probably you might have to go back and change a few things, but it will be in th interest of making this process better for everyone. So do be prepared for some back and forth. Developers who maintain open source also expect that you follow certain guidelines. These guidelines ensure that developers are able quickly give feedback on your contribution and how to make it better. Most probably you might have to go back and change a few things, but it will be in th interest of making this process better for everyone. So do be prepared for some back and forth.

91
docs/easy_install.md Normal file
View File

@ -0,0 +1,91 @@
# Easy Install Script
- This script will install the pre-requisites, install bench and setup an ERPNext site `(site1.local under frappe-bench)`
- Passwords for Frappe Administrator and MariaDB (root) will be asked and saved under `~/passwords.txt`
- MariaDB (root) password may be `password` on a fresh server
- You can then login as **Administrator** with the Administrator password
- The log file is saved under `/tmp/logs/install_bench.log` in case you run into any issues during the install.
- If you find any problems, post them on the forum: [https://discuss.erpnext.com](https://discuss.erpnext.com/tags/installation_problem) under the "Install / Update" category.
---
## What will this script do?
- Install all the pre-requisites
- Install the command line `bench` (under ~/.bench)
- Create a new bench (a folder that will contain your entire frappe/erpnext setup at ~/frappe-bench)
- Create a new ERPNext site on the bench (site1.local)
---
## Getting started with easy install...
Open your Terminal and enter:
#### 0. Setup user & Download the install script
If you are on a fresh server and logged in as root, at first create a dedicated user for frappe
& equip this user with sudo privileges
```
adduser [frappe-user]
usermod -aG sudo [frappe-user]
```
*(it is very common to use "frappe" as frappe-username, but this comes with the security flaw of ["frappe" ranking very high](https://www.reddit.com/r/dataisbeautiful/comments/b3sirt/i_deployed_over_a_dozen_cyber_honeypots_all_over/?st=JTJ0SC0Q&sh=76e05240) in as a username challenged in hacking attempts. So, for production sites it is highly recommended to use a custom username harder to guess)*
Switch to `[frappe-user]` (using `su [frappe-user]`) and start the setup
wget https://raw.githubusercontent.com/frappe/bench/master/playbooks/install.py
#### 1. Run the install script
sudo python3 install.py
*Note: `user` flag to create a user and install using that user (By default, the script will create a user with the username `frappe` if the --user flag is not used)*
For production or development, append the `--production` or `--develop` flag to the command respectively.
sudo python3 install.py --production --user [frappe-user]
or
sudo python3 install.py --develop
sudo python3 install.py --develop --user [frappe-user]
sudo python3 install.py --production --user [frappe-user] --container
*Note: `container` flag to install inside a container (this will prevent the `/proc/sys/vm/swappiness: Read-only` file system error)*
python3 install.py --production --version 11 --user [frappe-user]
use --version flag to install specific version
python3 install.py --production --version 11 --python python2.7 --user [frappe-user]
use --python flag to specify virtual environments python version, by default script setup python3
---
## How do I start ERPNext
1. For development: Go to your bench folder (`frappe-bench` by default) and start the bench with `bench start`
2. For production: Your process will be setup and managed by `nginx` and `supervisor`. Checkout [Setup Production](https://frappe.io/docs/user/en/bench/guides/setup-production.html) for more information.
---
## An error occured mid installation?
TLDR; Save the logs!
1. The easy install script starts multiple processes to install prerequisites, system dependencies, requirements, sets up locales, configuration files, etc.
2. The script pipes all these process outputs and saves it under `/tmp/log/{easy-install-filename}.log` as prompted by the script in the beginning of the script or/and if something went wrong again.
3. Retain this log file and share it in case you need help with proceeding with the install. Since, the file's saved under `/tmp` it'll be cleared by the system after a reboot. Be careful to save it elsewhere if needed!
3. A lot of things can go wrong in setting up the environment due to prior settings, company protocols or even breaking changes in system packages and their dependencies.
4. Sharing your logfile in any issues opened related to this can help us find solutions to it faster and make the sript better!

38
docs/installation.md Normal file
View File

@ -0,0 +1,38 @@
### Requirements
You will need a computer/server. Options include:
- A Normal Computer/VPS/Baremetal Server: This is strongly recommended. Frappe/ERPNext installs properly and works well on these
- A Raspberry Pi, SAN Appliance, Network Router, Gaming Console, etc.: Although you may be able to install Frappe/ERPNext on specialized hardware, it is unlikely to work well and will be difficult for us to support. Strongly consider using a normal computer/VPS/baremetal server instead. **We do not support specialized hardware**.
- A Toaster, Car, Firearm, Thermostat, etc.: Yes, many modern devices now have embedded computing capability. We live in interesting times. However, you should not install Frappe/ERPNext on these devices. Instead, install it on a normal computer/VPS/baremetal server. **We do not support installing on noncomputing devices**.
To install the Frappe/ERPNext server software, you will need an operating system on your normal computer which is not Windows. Note that the command line interface does work on Windows, and you can use Frappe/ERPNext from any operating system with a web browser. However, the server software does not run on Windows. It does run on other operating systems, so choose one of these instead:
- Linux: Ubuntu, Debian, CentOS are the preferred distros and are tested. [Arch Linux](https://github.com/frappe/bench/wiki/Install-ERPNext-on-ArchLinux) can also be used
- Mac OS X
### Manual Install
To manually install frappe/erpnext, you can follow this [this wiki](https://github.com/frappe/frappe/wiki/The-Hitchhiker%27s-Guide-to-Installing-Frappe-on-Linux) for Linux and [this wiki](https://github.com/frappe/frappe/wiki/The-Hitchhiker's-Guide-to-Installing-Frappe-on-Mac-OS-X) for MacOS. It gives an excellent explanation about the stack. You can also follow the steps mentioned below:
#### 1. Install Prerequisites
<pre>
• Python 3.6+
• Node.js 12
• Redis 5 (caching and realtime updates)
• MariaDB 10.3 / Postgres 9.5 (to run database driven apps)
• yarn 1.12+ (js dependency manager)
• pip 15+ (py dependency manager)
• cron (scheduled jobs)
• wkhtmltopdf (version 0.12.5 with patched qt) (for pdf generation)
• Nginx (for production)
</pre>
#### 2. Install Bench
Install bench as a *non root* user,
git clone https://github.com/frappe/bench ~/.bench
pip3 install --user -e ~/.bench
Note: Please do not remove the bench directory the above commands will create

View File

@ -1,17 +1,118 @@
# wget setup_frappe.py | python3 #!/usr/bin/env python3
import os, sys, subprocess, getpass, json, multiprocessing, shutil, platform import os, sys, subprocess, getpass, json, multiprocessing, shutil, platform, warnings, datetime
from distutils.spawn import find_executable
tmp_bench_repo = '/tmp/.bench' tmp_bench_repo = os.path.join('/', 'tmp', '.bench')
tmp_log_folder = os.path.join('/', 'tmp', 'logs')
execution_timestamp = datetime.datetime.utcnow()
execution_day = "{:%Y-%m-%d}".format(execution_timestamp)
execution_time = "{:%H:%M}".format(execution_timestamp)
log_file_name = "easy-install__{0}__{1}.log".format(execution_day, execution_time.replace(':', '-'))
log_path = os.path.join(tmp_log_folder, log_file_name)
log_stream = sys.stdout
def install_bench(args):
check_distribution_compatibility() def log(message, level=0):
check_brew_installed() levels = {
0: '\033[94m', # normal
1: '\033[92m', # success
2: '\033[91m', # fail
3: '\033[93m' # warn/suggest
}
start = levels.get(level) or ''
end = '\033[0m'
print(start + message + end)
def setup_log_stream(args):
global log_stream
sys.stderr = sys.stdout
if not args.verbose:
if not os.path.exists(tmp_log_folder):
os.makedirs(tmp_log_folder)
log_stream = open(log_path, 'w')
log("Logs are saved under {0}".format(log_path), level=3)
print("Install script run at {0} on {1}\n\n".format(execution_time, execution_day), file=log_stream)
def check_environment():
needed_environ_vars = ['LANG', 'LC_ALL']
message = ''
for var in needed_environ_vars:
if var not in os.environ:
message += "\nexport {0}=C.UTF-8".format(var)
if message:
log("Bench's CLI needs these to be defined!", level=3)
log("Run the following commands in shell: {0}".format(message), level=2)
sys.exit()
def check_system_package_managers():
if 'Darwin' in os.uname():
if not shutil.which('brew'):
raise Exception('''
Please install brew package manager before proceeding with bench setup. Please run following
to install brew package manager on your machine,
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
''')
if 'Linux' in os.uname():
if not any([shutil.which(x) for x in ['apt-get', 'yum']]):
raise Exception('Cannot find any compatible package manager!')
def check_distribution_compatibility():
dist_name, dist_version = get_distribution_info()
supported_dists = {
'macos': [10.9, 10.10, 10.11, 10.12],
'ubuntu': [14, 15, 16, 18, 19],
'debian': [8, 9],
'centos': [7]
}
log("Checking System Compatibility...")
if dist_name in supported_dists:
if float(dist_version) in supported_dists[dist_name]:
log("{0} {1} is compatible!".format(dist_name, dist_version), level=1)
else:
log("{0} {1} is detected".format(dist_name, dist_version), level=1)
log("Install on {0} {1} instead".format(dist_name, supported_dists[dist_name][-1]), level=3)
else:
log("Sorry, the installer doesn't support {0}. Aborting installation!".format(dist_name), level=2)
def get_distribution_info():
# return distribution name and major version
if platform.system() == "Linux":
current_dist = platform.dist()
return current_dist[0].lower(), current_dist[1].rsplit('.')[0]
elif platform.system() == "Darwin":
current_dist = platform.mac_ver()
return "macos", current_dist[0].rsplit('.', 1)[0]
def run_os_command(command_map):
'''command_map is a dictionary of {'executable': command}. For ex. {'apt-get': 'sudo apt-get install -y python2.7'}'''
success = True
for executable, commands in command_map.items():
if shutil.which(executable):
if isinstance(commands, str):
commands = [commands]
for command in commands:
returncode = subprocess.check_call(command, shell=True, stdout=log_stream, stderr=sys.stderr)
success = success and (returncode == 0)
return success
def install_prerequisites():
# pre-requisites for bench repo cloning # pre-requisites for bench repo cloning
install_package('curl') run_os_command({
install_package('wget')
success = run_os_command({
'apt-get': [ 'apt-get': [
'sudo apt-get update', 'sudo apt-get update',
'sudo apt-get install -y git build-essential python3-setuptools python3-dev libffi-dev' 'sudo apt-get install -y git build-essential python3-setuptools python3-dev libffi-dev'
@ -19,54 +120,48 @@ def install_bench(args):
'yum': [ 'yum': [
'sudo yum groupinstall -y "Development tools"', 'sudo yum groupinstall -y "Development tools"',
'sudo yum install -y epel-release redhat-lsb-core git python-setuptools python-devel openssl-devel libffi-devel' 'sudo yum install -y epel-release redhat-lsb-core git python-setuptools python-devel openssl-devel libffi-devel'
], ]
# epel-release is required to install redis, so installing it before the playbook-run.
# redhat-lsb-core is required, so that ansible can set ansible_lsb variable
}) })
if not find_executable("git"): install_package('curl')
success = run_os_command({ install_package('wget')
'brew': 'brew install git' install_package('git')
}) install_package('pip3', 'python3-pip')
if not success:
print('Could not install pre-requisites. Please check for errors or install them manually.')
return
# secure pip installation
if find_executable('pip'):
run_os_command({
'pip': 'sudo pip install --upgrade setuptools cryptography pip'
})
else:
if not os.path.exists("get-pip.py"):
run_os_command({
'wget': 'wget https://bootstrap.pypa.io/get-pip.py'
})
success = run_os_command({
'python3': 'sudo python3 get-pip.py --force-reinstall'
})
if success:
dist_name, dist_version = get_distribution_info()
if dist_name == 'centos':
run_os_command({
'pip': 'sudo pip install --upgrade --ignore-installed requests'
})
else:
run_os_command({
'pip': 'sudo pip install --upgrade requests'
})
success = run_os_command({ success = run_os_command({
'pip': "sudo pip install --upgrade setuptools cryptography ansible==2.8.5 pip" 'python3': "sudo -H python3 -m pip install --upgrade setuptools cryptography ansible==2.8.5 pip"
}) })
if not success: if not (success or shutil.which('ansible')):
could_not_install('Ansible') could_not_install('Ansible')
def could_not_install(package):
raise Exception('Could not install {0}. Please install it manually.'.format(package))
def is_sudo_user():
return os.geteuid() == 0
def install_package(package, package_name=None):
if shutil.which(package):
log("{0} already installed!".format(package), level=1)
else:
log("Installing {0}...".format(package))
package_name = package_name or package
success = run_os_command({
'apt-get': ['sudo apt-get install -y {0}'.format(package_name)],
'yum': ['sudo yum install -y {0}'.format(package_name)],
'brew': ['brew install {0}'.format(package_name)]
})
if success:
log("{0} installed!".format(package), level=1)
return success
could_not_install(package)
def install_bench(args):
# clone bench repo # clone bench repo
if not args.run_travis: if not args.run_travis:
clone_bench_repo(args) clone_bench_repo(args)
@ -134,107 +229,32 @@ def install_bench(args):
# Will install ERPNext production setup by default # Will install ERPNext production setup by default
run_playbook('site.yml', sudo=True, extra_vars=extra_vars) run_playbook('site.yml', sudo=True, extra_vars=extra_vars)
# # Will do changes for production if --production flag is passed
# if args.production:
# run_playbook('production.yml', sudo=True, extra_vars=extra_vars)
if os.path.exists(tmp_bench_repo): if os.path.exists(tmp_bench_repo):
shutil.rmtree(tmp_bench_repo) shutil.rmtree(tmp_bench_repo)
def check_distribution_compatibility():
supported_dists = {'ubuntu': [14, 15, 16, 18, 19], 'debian': [8, 9, 10],
'centos': [7], 'macos': [10.9, 10.10, 10.11, 10.12]}
dist_name, dist_version = get_distribution_info()
if dist_name in supported_dists:
if float(dist_version) in supported_dists[dist_name]:
return
print("Sorry, the installer doesn't support {0} {1}. Aborting installation!".format(dist_name, dist_version))
if dist_name in supported_dists:
print("Install on {0} {1} instead".format(dist_name, supported_dists[dist_name][-1]))
sys.exit(1)
def get_distribution_info():
# return distribution name and major version
if platform.system() == "Linux":
current_dist = platform.dist()
return current_dist[0].lower(), current_dist[1].rsplit('.')[0]
elif platform.system() == "Darwin":
current_dist = platform.mac_ver()
return "macos", current_dist[0].rsplit('.', 1)[0]
def install_package(package):
package_exec = find_executable(package)
if not package_exec:
success = run_os_command({
'apt-get': ['sudo apt-get install -y {0}'.format(package)],
'yum': ['sudo yum install -y {0}'.format(package)]
})
else:
return
if not success:
could_not_install(package)
def check_brew_installed():
if 'Darwin' not in os.uname():
return
brew_exec = find_executable('brew')
if not brew_exec:
raise Exception('''
Please install brew package manager before proceeding with bench setup. Please run following
to install brew package manager on your machine,
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
''')
def clone_bench_repo(args): def clone_bench_repo(args):
'''Clones the bench repository in the user folder''' '''Clones the bench repository in the user folder'''
if os.path.exists(tmp_bench_repo):
return 0
elif args.without_bench_setup:
clone_path = os.path.join(os.path.expanduser('~'), 'bench')
else:
clone_path = tmp_bench_repo
branch = args.bench_branch or 'master' branch = args.bench_branch or 'master'
repo_url = args.repo_url or 'https://github.com/frappe/bench' repo_url = args.repo_url or 'https://github.com/frappe/bench'
if os.path.exists(tmp_bench_repo):
return 0
elif args.without_bench_setup:
clone_path = os.path.join(os.path.expanduser('~'), 'bench')
else:
clone_path = tmp_bench_repo
success = run_os_command( success = run_os_command(
{'git': 'git clone {repo_url} {bench_repo} --depth 1 --branch {branch}'.format( {'git': 'git clone --quiet {repo_url} {bench_repo} --depth 1 --branch {branch}'.format(
repo_url=repo_url, bench_repo=clone_path, branch=branch)} repo_url=repo_url, bench_repo=clone_path, branch=branch)}
) )
return success return success
def run_os_command(command_map):
'''command_map is a dictionary of {'executable': command}. For ex. {'apt-get': 'sudo apt-get install -y python2.7'} '''
success = True
for executable, commands in list(command_map.items()):
if find_executable(executable):
if isinstance(commands, str):
commands = [commands]
for command in commands: def passwords_didnt_match(context=''):
returncode = subprocess.check_call(command, shell=True) log("{} passwords did not match!".format(context), level=3)
success = success and ( returncode == 0 )
break
return success
def could_not_install(package):
raise Exception('Could not install {0}. Please install it manually.'.format(package))
def is_sudo_user():
return os.geteuid() == 0
def get_passwords(args): def get_passwords(args):
@ -242,7 +262,7 @@ def get_passwords(args):
Returns a dict of passwords for further use Returns a dict of passwords for further use
and creates passwords.txt in the bench user's home directory and creates passwords.txt in the bench user's home directory
""" """
log("Input MySQL and Frappe Administrator passwords:")
ignore_prompt = args.run_travis or args.without_bench_setup ignore_prompt = args.run_travis or args.without_bench_setup
mysql_root_password, admin_password = '', '' mysql_root_password, admin_password = '', ''
passwords_file_path = os.path.join(os.path.expanduser('~' + args.user), 'passwords.txt') passwords_file_path = os.path.join(os.path.expanduser('~' + args.user), 'passwords.txt')
@ -269,6 +289,7 @@ def get_passwords(args):
conf_mysql_passwd = getpass.unix_getpass(prompt='Re-enter mysql root password: ') conf_mysql_passwd = getpass.unix_getpass(prompt='Re-enter mysql root password: ')
if mysql_root_password != conf_mysql_passwd or mysql_root_password == '': if mysql_root_password != conf_mysql_passwd or mysql_root_password == '':
passwords_didnt_match("MySQL")
mysql_root_password = '' mysql_root_password = ''
continue continue
@ -278,6 +299,7 @@ def get_passwords(args):
conf_admin_passswd = getpass.unix_getpass(prompt='Re-enter Administrator password: ') conf_admin_passswd = getpass.unix_getpass(prompt='Re-enter Administrator password: ')
if admin_password != conf_admin_passswd or admin_password == '': if admin_password != conf_admin_passswd or admin_password == '':
passwords_didnt_match("Administrator")
admin_password = '' admin_password = ''
continue continue
@ -294,7 +316,7 @@ def get_passwords(args):
with open(passwords_file_path, 'w') as f: with open(passwords_file_path, 'w') as f:
json.dump(passwords, f, indent=1) json.dump(passwords, f, indent=1)
print('Passwords saved at ~/passwords.txt') log('Passwords saved at ~/passwords.txt')
return passwords return passwords
@ -302,13 +324,15 @@ def get_passwords(args):
def get_extra_vars_json(extra_args): def get_extra_vars_json(extra_args):
# We need to pass production as extra_vars to the playbook to execute conditionals in the # We need to pass production as extra_vars to the playbook to execute conditionals in the
# playbook. Extra variables can passed as json or key=value pair. Here, we will use JSON. # playbook. Extra variables can passed as json or key=value pair. Here, we will use JSON.
json_path = os.path.join('/tmp', 'extra_vars.json') json_path = os.path.join('/', 'tmp', 'extra_vars.json')
extra_vars = dict(list(extra_args.items())) extra_vars = dict(list(extra_args.items()))
with open(json_path, mode='w') as j: with open(json_path, mode='w') as j:
json.dump(extra_vars, j, indent=1, sort_keys=True) json.dump(extra_vars, j, indent=1, sort_keys=True)
return ('@' + json_path) return ('@' + json_path)
def run_playbook(playbook_name, sudo=False, extra_vars=None): def run_playbook(playbook_name, sudo=False, extra_vars=None):
args = ['ansible-playbook', '-c', 'local', playbook_name , '-vvvv'] args = ['ansible-playbook', '-c', 'local', playbook_name , '-vvvv']
@ -324,92 +348,69 @@ def run_playbook(playbook_name, sudo=False, extra_vars=None):
else: else:
cwd = os.path.join(os.path.expanduser('~'), 'bench') cwd = os.path.join(os.path.expanduser('~'), 'bench')
success = subprocess.check_call(args, cwd=os.path.join(cwd, 'playbooks')) success = subprocess.check_call(args, cwd=os.path.join(cwd, 'playbooks'), stdout=log_stream, stderr=sys.stderr)
return success return success
def parse_commandline_args(): def parse_commandline_args():
import argparse import argparse
parser = argparse.ArgumentParser(description='Frappe Installer') parser = argparse.ArgumentParser(description='Frappe Installer')
# Arguments develop and production are mutually exclusive both can't be specified together. # Arguments develop and production are mutually exclusive both can't be specified together.
# Hence, we need to create a group for discouraging use of both options at the same time. # Hence, we need to create a group for discouraging use of both options at the same time.
args_group = parser.add_mutually_exclusive_group() args_group = parser.add_mutually_exclusive_group()
args_group.add_argument('--develop', dest='develop', action='store_true', default=False, args_group.add_argument('--develop', dest='develop', action='store_true', default=False, help='Install developer setup')
help='Install developer setup') args_group.add_argument('--production', dest='production', action='store_true', default=False, help='Setup Production environment for bench')
parser.add_argument('--site', dest='site', action='store', default='site1.local', help='Specifiy name for your first ERPNext site')
args_group.add_argument('--production', dest='production', action='store_true', parser.add_argument('--without-site', dest='without_site', action='store_true', default=False)
default=False, help='Setup Production environment for bench') parser.add_argument('--verbose', dest='verbose', action='store_true', default=False, help='Run the script in verbose mode')
parser.add_argument('--site', dest='site', action='store', default='site1.local',
help='Specifiy name for your first ERPNext site')
parser.add_argument('--without-site', dest='without_site', action='store_true',
default=False)
parser.add_argument('--verbose', dest='verbosity', action='store_true', default=False,
help='Run the script in verbose mode')
parser.add_argument('--user', dest='user', help='Install frappe-bench for this user') parser.add_argument('--user', dest='user', help='Install frappe-bench for this user')
parser.add_argument('--bench-branch', dest='bench_branch', help='Clone a particular branch of bench repository') parser.add_argument('--bench-branch', dest='bench_branch', help='Clone a particular branch of bench repository')
parser.add_argument('--repo-url', dest='repo_url', help='Clone bench from the given url') parser.add_argument('--repo-url', dest='repo_url', help='Clone bench from the given url')
parser.add_argument('--frappe-repo-url', dest='frappe_repo_url', action='store', default='https://github.com/frappe/frappe', help='Clone frappe from the given url')
parser.add_argument('--frappe-repo-url', dest='frappe_repo_url', action='store', default='https://github.com/frappe/frappe', parser.add_argument('--frappe-branch', dest='frappe_branch', action='store', help='Clone a particular branch of frappe')
help='Clone frappe from the given url') parser.add_argument('--erpnext-repo-url', dest='erpnext_repo_url', action='store', default='https://github.com/frappe/erpnext', help='Clone erpnext from the given url')
parser.add_argument('--erpnext-branch', dest='erpnext_branch', action='store', help='Clone a particular branch of erpnext')
parser.add_argument('--frappe-branch', dest='frappe_branch', action='store', parser.add_argument('--without-erpnext', dest='without_erpnext', action='store_true', default=False, help='Prevent fetching ERPNext')
help='Clone a particular branch of frappe')
parser.add_argument('--erpnext-repo-url', dest='erpnext_repo_url', action='store', default='https://github.com/frappe/erpnext',
help='Clone erpnext from the given url')
parser.add_argument('--erpnext-branch', dest='erpnext_branch', action='store',
help='Clone a particular branch of erpnext')
parser.add_argument('--without-erpnext', dest='without_erpnext', action='store_true', default=False,
help='Prevent fetching ERPNext')
# direct provision to install versions # direct provision to install versions
parser.add_argument('--version', dest='version', action='store', default='12', type=int, parser.add_argument('--version', dest='version', action='store', default='12', type=int, help='Clone particular version of frappe and erpnext')
help='Clone particular version of frappe and erpnext')
# To enable testing of script using Travis, this should skip the prompt # To enable testing of script using Travis, this should skip the prompt
parser.add_argument('--run-travis', dest='run_travis', action='store_true', default=False, parser.add_argument('--run-travis', dest='run_travis', action='store_true', default=False, help=argparse.SUPPRESS)
help=argparse.SUPPRESS) parser.add_argument('--without-bench-setup', dest='without_bench_setup', action='store_true', default=False, help=argparse.SUPPRESS)
parser.add_argument('--without-bench-setup', dest='without_bench_setup', action='store_true', default=False,
help=argparse.SUPPRESS)
# whether to overwrite an existing bench # whether to overwrite an existing bench
parser.add_argument('--overwrite', dest='overwrite', action='store_true', default=False, parser.add_argument('--overwrite', dest='overwrite', action='store_true', default=False, help='Whether to overwrite an existing bench')
help='Whether to overwrite an existing bench')
# set passwords # set passwords
parser.add_argument('--mysql-root-password', dest='mysql_root_password', help='Set mysql root password') parser.add_argument('--mysql-root-password', dest='mysql_root_password', help='Set mysql root password')
parser.add_argument('--mariadb-version', dest='mariadb_version', default='10.4', help='Specify mariadb version') parser.add_argument('--mariadb-version', dest='mariadb_version', default='10.2', help='Specify mariadb version')
parser.add_argument('--admin-password', dest='admin_password', help='Set admin password') parser.add_argument('--admin-password', dest='admin_password', help='Set admin password')
parser.add_argument('--bench-name', dest='bench_name', help='Create bench with specified name. Default name is frappe-bench') parser.add_argument('--bench-name', dest='bench_name', help='Create bench with specified name. Default name is frappe-bench')
# Python interpreter to be used # Python interpreter to be used
parser.add_argument('--python', dest='python', default='python3', parser.add_argument('--python', dest='python', default='python3', help=argparse.SUPPRESS)
help=argparse.SUPPRESS
)
# LXC Support # LXC Support
parser.add_argument('--container', dest='container', default=False, action='store_true', parser.add_argument('--container', dest='container', default=False, action='store_true', help='Use if you\'re creating inside LXC')
help='Use if you\'re creating inside LXC'
)
args = parser.parse_args() args = parser.parse_args()
return args return args
if __name__ == '__main__': if __name__ == '__main__':
if sys.version[0] == '2':
if not raw_input("It is recommended to run this script with Python 3\nDo you still wish to continue? [Y/n]: ").lower() == "y":
sys.exit()
if not is_sudo_user():
log("Please run this script as a non-root user with sudo privileges", level=3)
sys.exit()
args = parse_commandline_args() args = parse_commandline_args()
install_bench(args) with warnings.catch_warnings():
warnings.simplefilter("ignore")
setup_log_stream(args)
check_distribution_compatibility()
check_system_package_managers()
check_environment()
install_prerequisites()
install_bench(args)
print('''Frappe/ERPNext has been successfully installed!''') log("Bench + Frappe + ERPNext has been successfully installed!")

View File

@ -2,24 +2,26 @@
- hosts: localhost - hosts: localhost
become: yes become: yes
become_user: root become_user: root
vars: vars:
bench_repo_path: "/Users/{{ ansible_user_id }}/.bench" bench_repo_path: "/Users/{{ ansible_user_id }}/.bench"
bench_path: "/Users/{{ ansible_user_id }}/frappe-bench" bench_path: "/Users/{{ ansible_user_id }}/frappe-bench"
tasks:
# install pre-requisites
- name: install prequisites
homebrew: name={{ item }} state=present
with_items:
- cmake
- redis
- mariadb
- nodejs
# install wkhtmltopdf tasks:
- name: cask installs - name: install prequisites
homebrew_cask: name={{ item }} state=present homebrew:
with_items: name:
- wkhtmltopdf - cmake
- redis
- mariadb
- nodejs
state: present
- name: install wkhtmltopdf
homebrew_cask:
name:
- wkhtmltopdf
state: present
- name: configure mariadb - name: configure mariadb
include: roles/mariadb/tasks/main.yml include: roles/mariadb/tasks/main.yml

View File

@ -14,7 +14,9 @@
when: tmp_bench.stat.exists and not bench_repo_register.stat.exists when: tmp_bench.stat.exists and not bench_repo_register.stat.exists
- name: install bench - name: install bench
pip: name={{ bench_repo_path }} extra_args='-e' pip:
name: '{{ bench_repo_path }}'
extra_args: '-e'
become: yes become: yes
become_user: root become_user: root
@ -25,9 +27,14 @@
when: overwrite when: overwrite
- name: Check whether bench exists - name: Check whether bench exists
stat: path="{{ bench_path }}" stat:
path: "{{ bench_path }}"
register: bench_stat register: bench_stat
- name: Fix permissions
become_user: root
command: chown {{ frappe_user }} -R /home/{{ frappe_user }}
- name: python3 bench init for develop - name: python3 bench init for develop
command: bench init {{ bench_path }} --frappe-path {{ frappe_repo_url }} --frappe-branch {{ frappe_branch }} --python {{ python }} command: bench init {{ bench_path }} --frappe-path {{ frappe_repo_url }} --frappe-branch {{ frappe_branch }} --python {{ python }}
args: args:

View File

@ -2,7 +2,7 @@
- name: Setup production - name: Setup production
become: yes become: yes
become_user: root become_user: root
command: bench setup production {{ frappe_user }} command: bench setup production {{ frappe_user }} --yes
args: args:
chdir: '{{ bench_path }}' chdir: '{{ bench_path }}'

View File

@ -31,10 +31,12 @@
# For Ubuntu / Debian # For Ubuntu / Debian
- name: Install ufw - name: Install ufw
apt: name={{ item }} state=present force=yes apt:
with_items: state: present
- python-selinux force: yes
- ufw pkg:
- python-selinux
- ufw
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian' when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: Enable Firewall - name: Enable Firewall

View File

@ -4,45 +4,51 @@
pip: name=pyOpenSSL version=16.2.0 pip: name=pyOpenSSL version=16.2.0
- name: install pillow prerequisites for Debian < 8 - name: install pillow prerequisites for Debian < 8
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- libjpeg8-dev - libjpeg8-dev
- libtiff4-dev - libtiff4-dev
- tcl8.5-dev - tcl8.5-dev
- tk8.5-dev - tk8.5-dev
when: ansible_distribution_version | version_compare('8', 'lt') state: present
when: ansible_distribution_version is version_compare('8', 'lt')
- name: install pillow prerequisites for Debian 8 - name: install pillow prerequisites for Debian 8
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- libjpeg62-turbo-dev - libjpeg62-turbo-dev
- libtiff5-dev - libtiff5-dev
- tcl8.5-dev - tcl8.5-dev
- tk8.5-dev - tk8.5-dev
when: ansible_distribution_version | version_compare('8', 'eq') state: present
when: ansible_distribution_version is version_compare('8', 'eq')
- name: install pillow prerequisites for Debian 9 - name: install pillow prerequisites for Debian 9
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- libjpeg62-turbo-dev - libjpeg62-turbo-dev
- libtiff5-dev - libtiff5-dev
- tcl8.5-dev - tcl8.5-dev
- tk8.5-dev - tk8.5-dev
when: ansible_distribution_version | version_compare('9', 'eq') state: present
when: ansible_distribution_version is version_compare('9', 'eq')
- name: install pillow prerequisites for Debian >= 10 - name: install pillow prerequisites for Debian >= 10
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- libjpeg62-turbo-dev - libjpeg62-turbo-dev
- libtiff5-dev - libtiff5-dev
- tcl8.6-dev - tcl8.6-dev
- tk8.6-dev - tk8.6-dev
when: ansible_distribution_version | version_compare('10', 'ge') state: present
when: ansible_distribution_version is version_compare('10', 'ge')
- name: install pdf prerequisites debian - name: install pdf prerequisites debian
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- libssl-dev - libssl-dev
state: present
force: yes
... ...

View File

@ -3,35 +3,37 @@
- name: Install prerequisites using apt-get - name: Install prerequisites using apt-get
become: yes become: yes
become_user: root become_user: root
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- dnsmasq - dnsmasq
- fontconfig - fontconfig
- git # Version control - git # Version control
- htop # Server stats - htop # Server stats
- libcrypto++-dev - libcrypto++-dev
- libfreetype6-dev - libfreetype6-dev
- liblcms2-dev - liblcms2-dev
- libwebp-dev - libwebp-dev
- libxext6 - libxext6
- libxrender1 - libxrender1
- libxslt1-dev - libxslt1-dev
- libxslt1.1 - libxslt1.1
- libffi-dev - libffi-dev
- ntp # Clock synchronization - ntp # Clock synchronization
- postfix # Mail Server - postfix # Mail Server
- python3-dev # Installing python developer suite - python3-dev # Installing python developer suite
- python-tk - python-tk
- screen # To aid ssh sessions with connectivity problems - screen # To aid ssh sessions with connectivity problems
- vim # Is that supposed to be a question!? - vim # Is that supposed to be a question!?
- xfonts-75dpi - xfonts-75dpi
- xfonts-base - xfonts-base
- zlib1g-dev - zlib1g-dev
- apt-transport-https - apt-transport-https
- libsasl2-dev - libsasl2-dev
- libldap2-dev - libldap2-dev
- libcups2-dev - libcups2-dev
- pv # Show progress during database restore - pv # Show progress during database restore
state: present
force: yes
- include_tasks: debian.yml - include_tasks: debian.yml
when: ansible_distribution == 'Debian' when: ansible_distribution == 'Debian'

View File

@ -9,18 +9,20 @@
tasks: tasks:
# install pre-requisites # install pre-requisites
- name: install prequisites - name: install prequisites
homebrew: name={{ item }} state=present homebrew:
with_items: name:
- cmake - cmake
- redis - redis
- mariadb - mariadb
- nodejs - nodejs
state: present
# install wkhtmltopdf # install wkhtmltopdf
- name: cask installs - name: cask installs
homebrew_cask: name={{ item }} state=present homebrew_cask:
with_items: name:
- wkhtmltopdf - wkhtmltopdf
state: present
- name: configure mariadb - name: configure mariadb
include_tasks: roles/mariadb/tasks/main.yml include_tasks: roles/mariadb/tasks/main.yml

View File

@ -10,42 +10,43 @@
- name: "Setup prerequisites using yum" - name: "Setup prerequisites using yum"
become: yes become: yes
become_user: root become_user: root
yum: name={{ item }} state=present yum:
with_items: name:
- bzip2-devel - bzip2-devel
- cronie - cronie
- dnsmasq - dnsmasq
- freetype-devel - freetype-devel
- git - git
- htop - htop
- lcms2-devel - lcms2-devel
- libjpeg-devel - libjpeg-devel
- libtiff-devel - libtiff-devel
- libffi-devel - libffi-devel
- libwebp-devel - libwebp-devel
- libXext - libXext
- libXrender - libXrender
- libzip-devel - libzip-devel
- libffi-devel - libffi-devel
- ntp - ntp
- openssl-devel - openssl-devel
- postfix - postfix
- python36u - python36u
- python-devel - python-devel
- python-setuptools - python-setuptools
- python-pip - python-pip
- redis - redis
- screen - screen
- sudo - sudo
- tcl-devel - tcl-devel
- tk-devel - tk-devel
- vim - vim
- which - which
- xorg-x11-fonts-75dpi - xorg-x11-fonts-75dpi
- xorg-x11-fonts-Type1 - xorg-x11-fonts-Type1
- zlib-devel - zlib-devel
- openssl-devel - openssl-devel
- openldap-devel - openldap-devel
- libselinux-python - libselinux-python
- cups-libs - cups-libs
state: present
... ...

View File

@ -1,34 +1,41 @@
--- ---
- name: install pillow prerequisites for Ubuntu < 14.04 - name: install pillow prerequisites for Ubuntu < 14.04
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- libjpeg8-dev - libjpeg8-dev
- libtiff4-dev - libtiff4-dev
- tcl8.5-dev - tcl8.5-dev
- tk8.5-dev - tk8.5-dev
when: ansible_distribution_version | version_compare('14.04', 'lt') state: present
force: yes
when: ansible_distribution_version is version_compare('14.04', 'lt')
- name: install pillow prerequisites for Ubuntu >= 14.04 - name: install pillow prerequisites for Ubuntu >= 14.04
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- libjpeg8-dev - libjpeg8-dev
- libtiff5-dev - libtiff5-dev
- tcl8.6-dev - tcl8.6-dev
- tk8.6-dev - tk8.6-dev
when: ansible_distribution_version | version_compare('14.04', 'ge') state: present
force: yes
when: ansible_distribution_version is version_compare('14.04', 'ge')
- name: install pdf prerequisites for Ubuntu < 18.04 - name: install pdf prerequisites for Ubuntu < 18.04
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- libssl-dev - libssl-dev
when: ansible_distribution_version | version_compare('18.04', 'lt') state: present
force: yes
when: ansible_distribution_version is version_compare('18.04', 'lt')
- name: install pdf prerequisites for Ubuntu >= 18.04 - name: install pdf prerequisites for Ubuntu >= 18.04
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- libssl1.0-dev - libssl1.0-dev
when: ansible_distribution_version | version_compare('18.04', 'ge') state: present
force: yes
when: ansible_distribution_version is version_compare('18.04', 'ge')
... ...

View File

@ -1,9 +1,10 @@
--- ---
- name: Install deps - name: Install deps
yum: name="{{item}}" state=present yum:
with_items: name:
- policycoreutils-python - policycoreutils-python
- selinux-policy-devel - selinux-policy-devel
state: present
when: ansible_distribution == 'CentOS' when: ansible_distribution == 'CentOS'
- name: Check enabled SELinux modules - name: Check enabled SELinux modules

View File

@ -3,11 +3,16 @@
template: src=mariadb_centos.repo.j2 dest=/etc/yum.repos.d/mariadb.repo owner=root group=root mode=0644 template: src=mariadb_centos.repo.j2 dest=/etc/yum.repos.d/mariadb.repo owner=root group=root mode=0644
- name: Install MariaDB - name: Install MariaDB
yum: name={{ item }} enablerepo=mariadb state=present yum:
with_items: name:
- MariaDB-server - MariaDB-server
- MariaDB-client - MariaDB-client
enablerepo: mariadb
state: present
- name: Install MySQLdb Python package for secure installations. - name: Install MySQLdb Python package for secure installations.
yum: name=MySQL-python state=present yum:
name:
- MySQL-python
state: present
when: mysql_secure_installation and mysql_root_password is defined when: mysql_secure_installation and mysql_root_password is defined

View File

@ -1,11 +1,17 @@
--- ---
- name: Add apt key for mariadb for Debian <= 8 - name: Add apt key for mariadb for Debian <= 8
apt_key: keyserver=hkp://keyserver.ubuntu.com:80 id=0xcbcb082a1bb943db state=present apt_key: keyserver=hkp://keyserver.ubuntu.com:80 id=0xcbcb082a1bb943db state=present
when: ansible_distribution_major_version | version_compare('8', 'le') when: ansible_distribution_major_version is version_compare('8', 'le')
- name: Install dirmngr for apt key for mariadb for Debian > 8
apt:
pkg: dirmngr
state: present
when: ansible_distribution_major_version is version_compare('8', 'gt')
- name: Add apt key for mariadb for Debian > 8 - name: Add apt key for mariadb for Debian > 8
apt_key: keyserver=hkp://keyserver.ubuntu.com:80 id=0xF1656F24C74CD1D8 state=present apt_key: keyserver=hkp://keyserver.ubuntu.com:80 id=0xF1656F24C74CD1D8 state=present
when: ansible_distribution_major_version | version_compare('8', 'gt') when: ansible_distribution_major_version is version_compare('8', 'gt')
- name: Add apt repository - name: Add apt repository
apt_repository: apt_repository:
@ -21,11 +27,13 @@
shell: export DEBIAN_FRONTEND=noninteractive shell: export DEBIAN_FRONTEND=noninteractive
- name: apt-get install - name: apt-get install
apt: pkg={{ item }} update_cache=yes state=present apt:
with_items: pkg:
- mariadb-server - mariadb-server
- mariadb-client - mariadb-client
- mariadb-common - mariadb-common
- libmariadbclient18 - libmariadbclient18
- python3-mysqldb - python3-mysqldb
update_cache: yes
state: present
... ...

View File

@ -9,7 +9,12 @@
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version|int >= 16 when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version|int >= 16
- name: Add configuration - name: Add configuration
template: src={{ mysql_conf_tpl }} dest={{ mysql_conf_dir[ansible_distribution] }}/{{ mysql_conf_file }} owner=root group=root mode=0644 template:
src: '{{ mysql_conf_tpl }}'
dest: '{{ mysql_conf_dir[ansible_distribution] }}/{{ mysql_conf_file }}'
owner: root
group: root
mode: 0644
when: mysql_conf_tpl != 'change_me' and ansible_distribution != 'Debian' when: mysql_conf_tpl != 'change_me' and ansible_distribution != 'Debian'
notify: restart mysql notify: restart mysql
@ -17,7 +22,12 @@
when: ansible_distribution == 'Debian' when: ansible_distribution == 'Debian'
- name: Add configuration - name: Add configuration
template: src={{ mysql_conf_tpl }} dest={{ mysql_conf_dir[ansible_distribution] }}/{{ mysql_conf_file }} owner=root group=root mode=0644 template:
src: '{{ mysql_conf_tpl }}'
dest: '{{ mysql_conf_dir[ansible_distribution] }}/{{ mysql_conf_file }}'
owner: root
group: root
mode: 0644
when: mysql_conf_tpl != 'change_me' and ansible_distribution == 'Debian' when: mysql_conf_tpl != 'change_me' and ansible_distribution == 'Debian'
notify: restart mysql notify: restart mysql
@ -44,7 +54,10 @@
when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian' when: ansible_distribution == 'Ubuntu' or ansible_distribution == 'Debian'
- name: Start and enable service - name: Start and enable service
service: name=mysql state=started enabled=yes service:
name: mysql
state: started
enabled: yes
- debug: - debug:
msg: "{{ mysql_root_password }}" msg: "{{ mysql_root_password }}"
@ -52,7 +65,8 @@
- include_tasks: mysql_secure_installation.yml - include_tasks: mysql_secure_installation.yml
when: mysql_root_password is defined when: mysql_root_password is defined
- debug: var=mysql_secure_installation - debug:
var: mysql_secure_installation
when: mysql_secure_installation and mysql_root_password is defined when: mysql_secure_installation and mysql_root_password is defined
... ...

View File

@ -16,12 +16,16 @@
changed_when: false changed_when: false
- name: Install MariaDB - name: Install MariaDB
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- mariadb-server - mariadb-server
- mariadb-client - mariadb-client
- libmariadbclient18 - libmariadbclient18
state: present
- name: Install MySQLdb Python package for secure installations. - name: Install MySQLdb Python package for secure installations.
apt: pkg=python3-mysqldb state=present apt:
pkg:
- python3-mysqldb
state: present
when: mysql_secure_installation and mysql_root_password is defined when: mysql_secure_installation and mysql_root_password is defined

View File

@ -16,12 +16,16 @@
changed_when: false changed_when: false
- name: Install MariaDB - name: Install MariaDB
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- mariadb-server - mariadb-server
- mariadb-client - mariadb-client
- libmariadbclient18 - libmariadbclient18
state: present
- name: Install MySQLdb Python package for secure installations. - name: Install MySQLdb Python package for secure installations.
apt: pkg=python3-mysqldb state=present apt:
pkg:
- python3-mysqldb
state: present
when: mysql_secure_installation and mysql_root_password is defined when: mysql_secure_installation and mysql_root_password is defined

View File

@ -3,16 +3,16 @@
apt_key: apt_key:
url: http://nginx.org/keys/nginx_signing.key url: http://nginx.org/keys/nginx_signing.key
state: present state: present
when: ansible_distribution == 'Debian' and ansible_distribution_version | version_compare('8', 'lt') when: ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('8', 'lt')
- name: Add nginx apt repository for Debian < 8 - name: Add nginx apt repository for Debian < 8
apt_repository: apt_repository:
repo: 'deb [arch=amd64,i386] http://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx' repo: 'deb [arch=amd64,i386] http://nginx.org/packages/debian/ {{ ansible_distribution_release }} nginx'
state: present state: present
when: ansible_distribution == 'Debian' and ansible_distribution_version | version_compare('8', 'lt') when: ansible_distribution == 'Debian' and ansible_distribution_version is version_compare('8', 'lt')
- name: Ensure nginx is installed. - name: Ensure nginx is installed.
apt: apt:
pkg: nginx pkg: nginx
state: installed state: present
default_release: "{{ nginx_default_release }}" default_release: "{{ nginx_default_release }}"

View File

@ -6,11 +6,7 @@
shell: "curl --silent --location https://deb.nodesource.com/setup_{{ node_version }}.x | bash -" shell: "curl --silent --location https://deb.nodesource.com/setup_{{ node_version }}.x | bash -"
- name: Install nodejs {{ node_version }} - name: Install nodejs {{ node_version }}
apt: package:
name: name: nodejs
- nodejs
- npm
state: present state: present
update_cache: yes
force: yes
... ...

View File

@ -1,9 +1,10 @@
--- ---
- name: Install ntpd - name: Install ntpd
yum: name="{{item}}" state=installed yum:
with_items: name:
- ntp - ntp
- ntpdate - ntpdate
state: present
when: ansible_distribution == 'CentOS' when: ansible_distribution == 'CentOS'
- name: Enable ntpd - name: Enable ntpd
@ -11,10 +12,11 @@
when: ansible_distribution == 'CentOS' when: ansible_distribution == 'CentOS'
- name: Install ntpd - name: Install ntpd
apt: name="{{item}}" state=installed apt:
with_items: pkg:
- ntp - ntp
- ntpdate - ntpdate
state: present
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
- name: Enable ntpd - name: Enable ntpd

View File

@ -1,6 +1,8 @@
--- ---
- name: Install unzip - name: Install unzip
apt: pkg={{ item }} update_cache=yes state=present apt:
with_items: pkg:
- unzip - unzip
update_cache: yes
state: present
... ...

View File

@ -19,19 +19,19 @@
file: file:
state: absent state: absent
path: /opt/packer path: /opt/packer
when: (packer.stat.exists) and (packer_version | version_compare('1.2.1', '<')) when: (packer.stat.exists) and (packer_version is version_compare('1.2.1', '<'))
- name: Download packer zip file - name: Download packer zip file
command: chdir=/opt/ wget https://releases.hashicorp.com/packer/1.2.1/packer_1.2.1_linux_amd64.zip command: chdir=/opt/ wget https://releases.hashicorp.com/packer/1.2.1/packer_1.2.1_linux_amd64.zip
when: (packer.stat.exists == False) or (packer_version | version_compare('1.2.1', '<')) when: (packer.stat.exists == False) or (packer_version is version_compare('1.2.1', '<'))
- name: Unzip the packer binary in /opt - name: Unzip the packer binary in /opt
command: chdir=/opt/ unzip packer_1.2.1_linux_amd64.zip command: chdir=/opt/ unzip packer_1.2.1_linux_amd64.zip
when: (packer.stat.exists == False) or (packer_version | version_compare('1.2.1', '<')) when: (packer.stat.exists == False) or (packer_version is version_compare('1.2.1', '<'))
- name: Remove the downloaded packer zip file - name: Remove the downloaded packer zip file
file: file:
state: absent state: absent
path: /opt/packer_1.2.1_linux_amd64.zip path: /opt/packer_1.2.1_linux_amd64.zip
when: (packer.stat.exists == False) or (packer_version | version_compare('1.2.1', '<')) when: (packer.stat.exists == False) or (packer_version is version_compare('1.2.1', '<'))
... ...

View File

@ -1,7 +1,8 @@
--- ---
- name: Install unzip - name: Install unzip
yum: name={{ item }} state=present yum:
with_items: name:
- unzip - unzip
state: present
... ...

View File

@ -1,21 +1,25 @@
--- ---
- name: Install yum packages - name: Install yum packages
yum: name={{ item }} state=present yum:
with_items: name:
- redis - redis
state: present
when: ansible_os_family == 'RedHat' when: ansible_os_family == 'RedHat'
# Prerequisite for Debian and Ubuntu # Prerequisite for Debian and Ubuntu
- name: Install apt packages - name: Install apt packages
apt: pkg={{ item }} state=present force=yes apt:
with_items: pkg:
- redis-server - redis-server
state: present
force: yes
when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu' when: ansible_distribution == 'Debian' or ansible_distribution == 'Ubuntu'
# Prerequisite for MACOS # Prerequisite for MACOS
- name: install prequisites for macos - name: install prequisites for macos
homebrew: name={{ item }} state=present homebrew:
with_items: name:
- redis - redis
state: present
when: ansible_distribution == 'MacOSX' when: ansible_distribution == 'MacOSX'
... ...

View File

@ -1,9 +1,10 @@
--- ---
- name: Install dependencies - name: Install dependencies
apt: pkg={{ item }} state=present apt:
with_items: pkg:
- apt-transport-https - apt-transport-https
- ca-certificates - ca-certificates
state: present
- name: Add VirtualBox to sources.list - name: Add VirtualBox to sources.list
apt_repository: apt_repository:
@ -23,7 +24,9 @@
when: (ansible_distribution == "Debian" and ansible_distribution_major_version < "8") or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "16") when: (ansible_distribution == "Debian" and ansible_distribution_major_version < "8") or (ansible_distribution == "Ubuntu" and ansible_distribution_major_version < "16")
- name: Install VirtualBox - name: Install VirtualBox
apt: pkg={{ item }} update_cache=yes state=present apt:
with_items: pkg:
- virtualbox-{{ virtualbox_version }} - virtualbox-{{ virtualbox_version }}
update_cache: yes
state: present
... ...

View File

@ -5,10 +5,11 @@
state: present state: present
- name: Install dependencies - name: Install dependencies
yum: name={{ item }} state=present yum:
with_items: name:
- kernel-devel - kernel-devel
- deltarpm - deltarpm
state: present
- copy: src=virtualbox_centos.repo dest=/etc/yum.repos.d/virtualbox.repo owner=root group=root mode=0644 force=no - copy: src=virtualbox_centos.repo dest=/etc/yum.repos.d/virtualbox.repo owner=root group=root mode=0644 force=no

View File

@ -1,20 +1,23 @@
--- ---
- name: install base fonts - name: install base fonts
yum: name={{ item }} state=present yum:
with_items: name:
- libXrender - libXrender
- libXext - libXext
- xorg-x11-fonts-75dpi - xorg-x11-fonts-75dpi
- xorg-x11-fonts-Type1 - xorg-x11-fonts-Type1
state: present
when: ansible_os_family == 'RedHat' when: ansible_os_family == 'RedHat'
- name: install base fonts - name: install base fonts
apt: name={{ item }} state=present force=yes apt:
with_items: pkg:
- libxrender1 - libxrender1
- libxext6 - libxext6
- xfonts-75dpi - xfonts-75dpi
- xfonts-base - xfonts-base
state: present
force: yes
when: ansible_os_family == 'Debian' when: ansible_os_family == 'Debian'
# wkhtmltopdf has been locked down to 0.12.3 intentionally since 0.12.4 has problems. # wkhtmltopdf has been locked down to 0.12.3 intentionally since 0.12.4 has problems.

View File

@ -2,7 +2,7 @@ Click==7.0
GitPython==2.1.11 GitPython==2.1.11
honcho==1.0.1 honcho==1.0.1
Jinja2==2.10.3 Jinja2==2.10.3
python_crontab==2.4.0 python-crontab==2.4.0
requests==2.22.0 requests==2.22.0
semantic_version==2.8.2 semantic_version==2.8.2
setuptools==40.8.0 setuptools==40.8.0