blob: 303c83b222b241015364cdb17122c3bc1a1a4737 [file] [log] [blame]
Rushabh Mehtae67d1fb2013-08-05 14:59:54 +05301# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
2# License: GNU General Public License v3. See license.txt
3
Rushabh Mehta54c15452013-07-16 12:05:41 +05304#!/usr/bin/env python
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +05305from __future__ import unicode_literals
Rushabh Mehta54c15452013-07-16 12:05:41 +05306import os, sys
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +05307
Rushabh Mehta54c15452013-07-16 12:05:41 +05308is_redhat = is_debian = None
9root_password = None
10
Pratik Vyasfe44d272013-10-24 23:59:53 +053011requirements = [
12 "MySQL-python",
13 "pytz==2013b",
14 "python-dateutil",
15 "jinja2",
16 "markdown2",
17 "termcolor",
18 "python-memcached",
19 "requests",
20 "chardet",
21 "dropbox",
Pratik Vyas4ec768b2013-10-28 21:57:59 +053022 "Werkzeug",
Pratik Vyasfe44d272013-10-24 23:59:53 +053023 "google-api-python-client ",
24 "pygeoip"
25]
26
Rushabh Mehta54c15452013-07-16 12:05:41 +053027def install(install_path=None):
Pratik Vyasfe44d272013-10-24 23:59:53 +053028 if os.getuid() != 0:
29 raise Exception, "Please run this script as root"
30
Rushabh Mehta54c15452013-07-16 12:05:41 +053031 install_pre_requisites()
Pratik Vyasfe44d272013-10-24 23:59:53 +053032
33 if os.environ.get('SUDO_UID'):
34 os.setuid(int(os.environ.get('SUDO_UID')))
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +053035
Rushabh Mehta54c15452013-07-16 12:05:41 +053036 if not install_path:
37 install_path = os.getcwd()
Pratik Vyasfe44d272013-10-24 23:59:53 +053038 setup_folders(install_path)
Rushabh Mehta54c15452013-07-16 12:05:41 +053039 install_erpnext(install_path)
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +053040
Rushabh Mehta54c15452013-07-16 12:05:41 +053041 post_install(install_path)
42
43def install_pre_requisites():
44 global is_redhat, is_debian
45 is_redhat, is_debian = validate_install()
46 if is_redhat:
47 install_using_yum()
48 elif is_debian:
49 install_using_apt()
50
51 install_python_modules()
52
53 print "-"*80
54 print "Pre-requisites Installed"
55 print "-"*80
56
57def validate_install():
58 import platform
59
60 # check os
61 operating_system = platform.system()
62 print "Operating System =", operating_system
63 if operating_system != "Linux":
64 raise Exception, "Sorry! This installer works only for Linux based Operating Systems"
65
66 # check python version
67 python_version = sys.version.split(" ")[0]
68 print "Python Version =", python_version
Pratik Vyasfe44d272013-10-24 23:59:53 +053069 if not (python_version and int(python_version.split(".")[0])==2 and int(python_version.split(".")[1]) >= 7):
Rushabh Mehta54c15452013-07-16 12:05:41 +053070 raise Exception, "Hey! ERPNext needs Python version to be 2.6+"
71
72 # check distribution
73 distribution = platform.linux_distribution()[0].lower().replace('"', '')
74 print "Distribution = ", distribution
Anand Doshib1b564c2013-07-29 11:44:26 +053075 is_redhat = distribution in ("redhat", "centos", "centos linux", "fedora")
Nabin Haitada70992013-08-20 10:58:07 +053076 is_debian = distribution in ("debian", "ubuntu", "elementary os", "linuxmint")
Rushabh Mehta54c15452013-07-16 12:05:41 +053077
78 if not (is_redhat or is_debian):
79 raise Exception, "Sorry! This installer works only with yum or apt-get package management"
80
81 return is_redhat, is_debian
82
83def install_using_yum():
Pratik Vyasfe44d272013-10-24 23:59:53 +053084 packages = "python python-setuptools gcc python-devel MySQL-python git memcached ntp vim-enhanced screen"
Rushabh Mehta54c15452013-07-16 12:05:41 +053085
86 print "-"*80
87 print "Installing Packages: (This may take some time)"
88 print packages
89 print "-"*80
90 exec_in_shell("yum install -y %s" % packages)
91
92 if not exec_in_shell("which mysql"):
93 packages = "mysql mysql-server mysql-devel"
94 print "Installing Packages:", packages
95 exec_in_shell("yum install -y %s" % packages)
96 exec_in_shell("service mysqld restart")
97
98 # set a root password post install
99 global root_password
100 print "Please create a password for root user of MySQL"
101 root_password = (get_root_password() or "erpnext").strip()
102 exec_in_shell('mysqladmin -u root password "%s"' % (root_password,))
103 print "Root password set as", root_password
104
105 # install htop
106 if not exec_in_shell("which htop"):
107 try:
108 exec_in_shell("cd /tmp && rpm -i --force http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm && yum install -y htop")
109 except:
110 pass
111
112 update_config_for_redhat()
113
114def update_config_for_redhat():
115 import re
116
Rushabh Mehta54c15452013-07-16 12:05:41 +0530117 # set to autostart on startup
118 for service in ("mysqld", "httpd", "memcached", "ntpd"):
119 exec_in_shell("chkconfig --level 2345 %s on" % service)
120 exec_in_shell("service %s restart" % service)
121
122def install_using_apt():
Anand Doshib1b564c2013-07-29 11:44:26 +0530123 exec_in_shell("apt-get update")
Pratik Vyasfe44d272013-10-24 23:59:53 +0530124 packages = "python python-setuptools python-dev build-essential python-pip python-mysqldb git memcached ntp vim screen htop"
Rushabh Mehta54c15452013-07-16 12:05:41 +0530125 print "-"*80
126 print "Installing Packages: (This may take some time)"
127 print packages
128 print "-"*80
129 exec_in_shell("apt-get install -y %s" % packages)
Pratik Vyas4ec768b2013-10-28 21:57:59 +0530130 global root_password
131 if not root_password:
132 root_password = get_root_password()
133 exec_in_shell("echo mysql-server mysql-server/root_password password %s | sudo debconf-set-selections" % root_password)
134 exec_in_shell("echo mysql-server mysql-server/root_password_again password %s | sudo debconf-set-selections" % root_password)
Rushabh Mehta54c15452013-07-16 12:05:41 +0530135
136 if not exec_in_shell("which mysql"):
137 packages = "mysql-server libmysqlclient-dev"
138 print "Installing Packages:", packages
139 exec_in_shell("apt-get install -y %s" % packages)
140
141 update_config_for_debian()
142
143def update_config_for_debian():
Pratik Vyasf4081c82013-10-28 14:43:00 +0530144 for service in ("mysql", "ntpd"):
Rushabh Mehta54c15452013-07-16 12:05:41 +0530145 exec_in_shell("service %s restart" % service)
146
147def install_python_modules():
Rushabh Mehta54c15452013-07-16 12:05:41 +0530148 print "-"*80
149 print "Installing Python Modules: (This may take some time)"
Rushabh Mehta54c15452013-07-16 12:05:41 +0530150 print "-"*80
151
Anand Doshie7d77ca2013-08-14 15:12:46 +0530152 if not exec_in_shell("which pip"):
153 exec_in_shell("easy_install pip")
154
155 exec_in_shell("pip install --upgrade pip")
Anand Doshi3a6f4f82013-09-12 19:10:05 +0530156 exec_in_shell("pip install --upgrade setuptools")
Anand Doshie7d77ca2013-08-14 15:12:46 +0530157 exec_in_shell("pip install --upgrade virtualenv")
Pratik Vyas4ec768b2013-10-28 21:57:59 +0530158 exec_in_shell("pip install {}".format(' '.join(requirements)))
Anand Doshi08352ca2013-07-17 08:24:50 +0530159
Rushabh Mehta54c15452013-07-16 12:05:41 +0530160def install_erpnext(install_path):
161 print
162 print "-"*80
163 print "Installing ERPNext"
164 print "-"*80
165
166 # ask for details
167 global root_password
168 if not root_password:
169 root_password = get_root_password()
170 test_root_connection(root_password)
171
172 db_name = raw_input("ERPNext Database Name: ")
173 if not db_name:
174 raise Exception, "Sorry! You must specify ERPNext Database Name"
175
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530176 # setup paths
Pratik Vyasfe44d272013-10-24 23:59:53 +0530177 sys.path = [".", "lib", "app"] + sys.path
178 import wnf
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530179
Rushabh Mehta54c15452013-07-16 12:05:41 +0530180 # install database, run patches, update schema
Pratik Vyasfe44d272013-10-24 23:59:53 +0530181 # setup_db(install_path, root_password, db_name)
182 wnf.install(db_name, root_password=root_password)
183
184 # setup_cron(install_path)
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530185
186def get_root_password():
187 # ask for root mysql password
188 import getpass
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530189 root_pwd = None
Rushabh Mehta54c15452013-07-16 12:05:41 +0530190 root_pwd = getpass.getpass("MySQL Root user's Password: ")
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530191 return root_pwd
192
193def test_root_connection(root_pwd):
Rushabh Mehta54c15452013-07-16 12:05:41 +0530194 out = exec_in_shell("mysql -u root %s -e 'exit'" % \
195 (("-p"+root_pwd) if root_pwd else "").replace('$', '\$').replace(' ', '\ '))
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530196 if "access denied" in out.lower():
197 raise Exception("Incorrect MySQL Root user's password")
Rushabh Mehta54c15452013-07-16 12:05:41 +0530198
199def setup_folders(install_path):
Rushabh Mehta54c15452013-07-16 12:05:41 +0530200 app = os.path.join(install_path, "app")
201 if not os.path.exists(app):
202 print "Cloning erpnext"
Pratik Vyasf64dfa12013-10-31 11:43:51 +0530203 exec_in_shell("cd %s && git clone https://github.com/webnotes/erpnext.git app" % install_path)
Rushabh Mehta54c15452013-07-16 12:05:41 +0530204 exec_in_shell("cd app && git config core.filemode false")
Anand Doshi7d3e75d2013-07-24 19:01:02 +0530205 if not os.path.exists(app):
206 raise Exception, "Couldn't clone erpnext repository"
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530207
Rushabh Mehta54c15452013-07-16 12:05:41 +0530208 lib = os.path.join(install_path, "lib")
209 if not os.path.exists(lib):
210 print "Cloning wnframework"
Pratik Vyasf64dfa12013-10-31 11:43:51 +0530211 exec_in_shell("cd %s && git clone https://github.com/webnotes/wnframework.git lib" % install_path)
Rushabh Mehta54c15452013-07-16 12:05:41 +0530212 exec_in_shell("cd lib && git config core.filemode false")
Anand Doshi7d3e75d2013-07-24 19:01:02 +0530213 if not os.path.exists(lib):
214 raise Exception, "Couldn't clone wnframework repository"
Rushabh Mehta54c15452013-07-16 12:05:41 +0530215
216 public = os.path.join(install_path, "public")
217 for p in [public, os.path.join(public, "files"), os.path.join(public, "backups"),
218 os.path.join(install_path, "logs")]:
219 if not os.path.exists(p):
220 os.mkdir(p)
221
222def setup_conf(install_path, db_name):
223 import os, string, random, re
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530224
Rushabh Mehta54c15452013-07-16 12:05:41 +0530225 # generate db password
226 char_range = string.ascii_letters + string.digits
227 db_password = "".join((random.choice(char_range) for n in xrange(16)))
228
229 # make conf file
230 with open(os.path.join(install_path, "lib", "conf", "conf.py"), "r") as template:
231 conf = template.read()
232
233 conf = re.sub("db_name.*", 'db_name = "%s"' % (db_name,), conf)
234 conf = re.sub("db_password.*", 'db_password = "%s"' % (db_password,), conf)
235
236 with open(os.path.join(install_path, "conf.py"), "w") as conf_file:
237 conf_file.write(conf)
238
239 return db_password
240
Rushabh Mehta54c15452013-07-16 12:05:41 +0530241def post_install(install_path):
Rushabh Mehta54c15452013-07-16 12:05:41 +0530242 print
243 print "-"*80
Pratik Vyasfe44d272013-10-24 23:59:53 +0530244 print "To start the development server, run lib/wnf.py --serve"
Anand Doshicf2cf382013-08-09 19:39:09 +0530245 print "-"*80
Rushabh Mehta54c15452013-07-16 12:05:41 +0530246 print "Installation complete"
Pratik Vyasfe44d272013-10-24 23:59:53 +0530247 print "Open your browser and go to http://localhost:8000"
Rushabh Mehta54c15452013-07-16 12:05:41 +0530248 print "Login using username = Administrator and password = admin"
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530249
Rushabh Mehta54c15452013-07-16 12:05:41 +0530250def exec_in_shell(cmd):
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530251 # using Popen instead of os.system - as recommended by python docs
Rushabh Mehta54c15452013-07-16 12:05:41 +0530252 from subprocess import Popen
253 import tempfile
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530254
Rushabh Mehta54c15452013-07-16 12:05:41 +0530255 with tempfile.TemporaryFile() as stdout:
256 with tempfile.TemporaryFile() as stderr:
257 p = Popen(cmd, shell=True, stdout=stdout, stderr=stderr)
258 p.wait()
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530259
Rushabh Mehta54c15452013-07-16 12:05:41 +0530260 stdout.seek(0)
261 out = stdout.read()
Nabin Hait096d3632013-10-17 17:01:14 +0530262 if out: out = out.decode('utf-8')
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530263
Rushabh Mehta54c15452013-07-16 12:05:41 +0530264 stderr.seek(0)
265 err = stderr.read()
Nabin Hait096d3632013-10-17 17:01:14 +0530266 if err: err = err.decode('utf-8')
Rushabh Mehtaa8f9aa02013-06-21 17:55:43 +0530267
Rushabh Mehta54c15452013-07-16 12:05:41 +0530268 if err and any((kw in err.lower() for kw in ["traceback", "error", "exception"])):
269 print out
270 raise Exception, err
271 else:
272 print "."
273
274 return out
275
276if __name__ == "__main__":
Nabin Hait096d3632013-10-17 17:01:14 +0530277 install()