1515import tempfile
1616import time
1717import urllib .parse
18+ import traceback
1819from argparse import SUPPRESS , Action , ArgumentError , ArgumentParser , HelpFormatter
1920from operator import itemgetter
2021from typing import Any , Dict , List , Optional
4041BUCKET_TYPE_COUCHBASE = "membase"
4142BUCKET_TYPE_MEMCACHED = "memcached"
4243
43- CB_BIN_PATH = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." , "bin" ))
44- CB_ETC_PATH = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." , "etc" , "couchbase" ))
45- CB_LIB_PATH = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." , "lib" ))
4644
47- if os .name == 'nt' :
48- CB_NS_EBIN_PATH = os .path .join (CB_LIB_PATH , "ns_server" , "ebin" )
49- CB_BABYSITTER_EBIN_PATH = os .path .join (CB_LIB_PATH , "ns_babysitter" , "ebin" )
50- else :
51- CB_NS_EBIN_PATH = os .path .join (CB_LIB_PATH , "ns_server" , "erlang" , "lib" , "ns_server" , "ebin" )
52- CB_BABYSITTER_EBIN_PATH = os .path .join (CB_LIB_PATH , "ns_server" , "erlang" , "lib" , "ns_babysitter" , "ebin" )
45+ def check_base_path (base_path ):
46+ required_dirs = ["bin" , "etc" , "lib" ]
47+ return all (os .path .exists (os .path .join (base_path , d )) for d in required_dirs )
5348
54- inetrc_file = os .path .join (CB_ETC_PATH , 'hosts.cfg' )
55- if os .path .isfile (inetrc_file ):
56- inetrc_file = inetrc_file .encode ('unicode-escape' ).decode ()
57- CB_INETRC_OPT = ['inetrc' , f'"{ inetrc_file } "' ]
58- else :
59- CB_INETRC_OPT = []
6049
61- # On MacOS the config is store in the users home directory
62- if platform .system () == "Darwin" :
63- CB_CFG_PATH = os .path .expanduser ("~/Library/Application Support/Couchbase/var/lib/couchbase" )
64- # erl script fails in OSX as it is unable to find COUCHBASE_TOP
65- os .environ ["COUCHBASE_TOP" ] = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." ))
66- else :
67- CB_CFG_PATH = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." , "var" , "lib" , "couchbase" ))
50+ def get_base_cb_path ():
51+ # Check if relative path exists
52+ base_path = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." ))
53+ if os .path .exists (base_path ) and check_base_path (base_path ):
54+ return base_path
6855
69- CB_MAN_PATH = os .path .abspath (os .path .join (os .path .dirname (__file__ ), ".." , ".." , "share" ))
56+ # If the base path is not at the relative path, then check the default path, which is platform dependent
57+ system = platform .system ()
58+ if system == "Darwin" :
59+ base_path = os .path .join (os .sep , "Applications" , "Couchbase Server.app" , "Contents" , "Resources" ,
60+ "couchbase-core" )
61+ elif system == "Windows" :
62+ base_path = os .path .join ("C:" + os .sep , "Program Files" , "couchbase" , "server" )
63+ elif system == "Linux" :
64+ base_path = os .path .join (os .sep , "opt" , "couchbase" )
65+ else :
66+ base_path = None
7067
71- if os .name == "nt" :
72- CB_MAN_PATH = os .path .join (CB_MAN_PATH , "doc" , "couchbase-cli" )
73- else :
74- CB_MAN_PATH = os .path .join (CB_MAN_PATH , "man" , "man1" )
68+ if base_path and check_base_path (base_path ):
69+ return base_path
70+
71+ return None
72+
73+
74+ def get_bin_path ():
75+ base_path = get_base_cb_path ()
76+ if not base_path :
77+ return None
78+
79+ return os .path .join (base_path , "bin" )
80+
81+
82+ def get_hosts_path ():
83+ base_path = get_base_cb_path ()
84+ if not base_path :
85+ return None
86+
87+ hosts_path = os .path .join (base_path , "etc" , "couchbase" , "hosts.cfg" )
88+ if os .path .isfile (hosts_path ):
89+ return hosts_path
90+
91+ return None
92+
93+
94+ def get_inetrc (hosts_path ):
95+ inetrc_file = hosts_path .encode ('unicode-escape' ).decode ()
96+ return ['inetrc' , f'"{ inetrc_file } "' ]
97+
98+
99+ def get_cfg_path ():
100+ base_path = get_base_cb_path ()
101+ if not base_path :
102+ return None
103+
104+ if platform .system () == "Darwin" :
105+ return os .path .expanduser ("~/Library/Application Support/Couchbase/var/lib/couchbase" )
106+
107+ return os .path .join (base_path , "var" , "lib" , "couchbase" )
108+
109+
110+ def get_lib_path ():
111+ base_path = get_base_cb_path ()
112+ if not base_path :
113+ return None
114+
115+ return os .path .join (base_path , "lib" )
116+
117+
118+ def get_ns_ebin_path ():
119+ lib_path = get_lib_path ()
120+ if not lib_path :
121+ return None
122+
123+ if platform .system () == "Windows" :
124+ return os .path .join (lib_path , "ns_server" , "ebin" )
125+
126+ return os .path .join (lib_path , "ns_server" , "erlang" , "lib" , "ns_server" , "ebin" )
127+
128+
129+ def get_man_path ():
130+ base_path = get_base_cb_path ()
131+ if not base_path :
132+ return None
133+
134+ share_path = os .path .join (base_path , "share" )
135+
136+ if platform .system () == "Windows" :
137+ return os .path .join (share_path , "doc" , "couchbase-cli" )
138+
139+ return os .path .join (share_path , "man" , "man1" )
75140
76141
77142def get_doc_page_name (command : str ) -> str :
@@ -539,14 +604,15 @@ def __call__(self, parser, namespace, values, option_string=None):
539604
540605 @staticmethod
541606 def _show_man_page (page ):
607+ man_path = get_man_path ()
542608 if os .name == "nt" :
543609 try :
544- subprocess .call (["rundll32.exe" , "url.dll,FileProtocolHandler" , os .path .join (CB_MAN_PATH , page )])
610+ subprocess .call (["rundll32.exe" , "url.dll,FileProtocolHandler" , os .path .join (man_path , page )])
545611 except OSError as e :
546612 _exit_if_errors (["Unable to open man page using your browser, %s" % e ])
547613 else :
548614 try :
549- subprocess .call (["man" , os .path .join (CB_MAN_PATH , page )])
615+ subprocess .call (["man" , os .path .join (man_path , page )])
550616 except OSError :
551617 _exit_if_errors (["Unable to open man page using the 'man' command, ensure it is on your path or"
552618 + "install a manual reader" ])
@@ -742,7 +808,7 @@ def __init__(self):
742808 group .add_argument ("-h" , "--help" , action = CBHelpAction , klass = self ,
743809 help = "Prints the short or long help message" )
744810 group .add_argument ("--config-path" , dest = "config_path" , metavar = "<path>" ,
745- default = CB_CFG_PATH , help = SUPPRESS )
811+ default = get_cfg_path () , help = "Overrides the default configuration path" )
746812
747813 def execute (self , opts ): # pylint: disable=useless-super-delegation
748814 super (LocalSubcommand , self ).execute (opts )
@@ -1737,6 +1803,9 @@ def __init__(self):
17371803 help = "The REST API port, defaults to 8091" )
17381804
17391805 def execute (self , opts ):
1806+ if opts .config_path is None :
1807+ _exit_if_errors (["Unable to locate the configuration path, please specify it using --config-path" ])
1808+
17401809 token = _exit_on_file_read_failure (os .path .join (opts .config_path , "localtoken" )).rstrip ()
17411810 rest = ClusterManager ("http://127.0.0.1:" + opts .port , "@localtoken" , token )
17421811 check_cluster_initialized (rest )
@@ -1774,6 +1843,9 @@ def __init__(self):
17741843
17751844 def execute (self , opts ):
17761845 if opts .send_password is not None :
1846+ if opts .config_path is None :
1847+ _exit_if_errors (["Unable to locate the configuration path, please specify it using --config-path" ])
1848+
17771849 portfile = os .path .join (opts .config_path , "couchbase-server.babysitter.smport" )
17781850 if not os .path .isfile (portfile ):
17791851 _exit_if_errors (["The node is down" ])
@@ -2078,6 +2150,9 @@ def __init__(self):
20782150 help = "The IP address of the cluster, defaults to localhost" )
20792151
20802152 def execute (self , opts ):
2153+ if opts .config_path is None :
2154+ _exit_if_errors (["Unable to locate the configuration path, please specify it using --config-path" ])
2155+
20812156 token = _exit_on_file_read_failure (os .path .join (opts .config_path , "localtoken" )).rstrip ()
20822157 ip = opts .ip if ":" not in opts .ip else "[" + opts .ip + "]"
20832158 rest = ClusterManager ("http://" + ip + ":" + opts .port , "@localtoken" , token )
@@ -2179,8 +2254,14 @@ def __init__(self):
21792254 group = self .parser .add_argument_group ("Server eshell options" )
21802255 group .add_argument ("--vm" , dest = "vm" , default = "ns_server" , metavar = "<name>" ,
21812256 help = "The vm to connect to" )
2182- group .add_argument ("--erl-path" , dest = "erl_path" , metavar = "<path>" , default = CB_BIN_PATH ,
2183- help = "Override the path to the erl executable" )
2257+ group .add_argument ("--erl-path" , dest = "erl_path" , metavar = "<path>" , default = get_bin_path (),
2258+ help = "Override the default path to the erl executable" )
2259+ group .add_argument ("--ns-ebin-path" , dest = "ns_ebin_path" , metavar = "<path>" , default = get_ns_ebin_path (),
2260+ help = "Override the default path to the ns_server ebin directory" )
2261+ group .add_argument ("--hosts-path" , dest = "hosts_path" , metavar = "<path>" , default = get_hosts_path (),
2262+ help = "Override the default path to the hosts.cfg file" )
2263+ group .add_argument ("--base-path" , dest = "base_path" , metavar = "<path>" , default = get_base_cb_path (),
2264+ help = "Override the default path to the Couchbase Server base directory" )
21842265
21852266 @rest_initialiser (version_check = True )
21862267 def execute (self , opts ):
@@ -2219,12 +2300,27 @@ def execute(self, opts):
22192300 _warning ("Cannot locate Couchbase erlang. Attempting to use non-Couchbase erlang" )
22202301 path = 'erl'
22212302
2303+ if not opts .erl_path :
2304+ _exit_if_errors (["directory containing erl executable not found, please specify it using --erl-path" ])
2305+
2306+ if not opts .ns_ebin_path :
2307+ _exit_if_errors (["ns_server ebin directory not found, please specify it using --ns-ebin-path" ])
2308+
2309+ if not opts .hosts_path :
2310+ _exit_if_errors (["hosts.cfg file not found, please specify it using --hosts-path" ])
2311+
2312+ if not opts .base_path :
2313+ _exit_if_errors (["Couchbase Server base directory not found, please specify it using --base-path" ])
2314+
22222315 with tempfile .NamedTemporaryFile () as temp :
22232316 temp .write (f'[{{preferred_local_proto,{ result ["addressFamily" ]} _tcp_dist}}].' .encode ())
22242317 temp .flush ()
22252318 temp_name = temp .name
22262319 env = os .environ .copy ()
22272320 env ["CB_COOKIE" ] = cookie
2321+ if platform .system () == "Darwin" :
2322+ # erl script fails in OSX as it is unable to find COUCHBASE_TOP
2323+ env ["COUCHBASE_TOP" ] = opts .base_path
22282324
22292325 args = [
22302326 path ,
@@ -2243,10 +2339,10 @@ def execute(self, opts):
22432339 'cb_epmd' ,
22442340 '-no_epmd' ,
22452341 '-pa' ,
2246- CB_NS_EBIN_PATH ,
2342+ opts . ns_ebin_path ,
22472343 '-kernel' ,
22482344 'dist_config_file' ,
2249- f'"{ temp_name } "' ] + CB_INETRC_OPT
2345+ f'"{ temp_name } "' ] + get_inetrc ( opts . hosts_path )
22502346
22512347 if opts .debug :
22522348 print (f'Running { " " .join (args )} ' )
0 commit comments