Пример #1
0
func execshell(line string, t *testing.T) {
	go_n1ql.SetPassthroughMode(true)
	var liner = liner.NewLiner()
	defer liner.Close()

	var b bytes.Buffer
	w := bufio.NewWriter(&b)
	command.SetWriter(w)

	errC, errS := ExecShellCmd(line, liner)
	w.Flush()
	if errC != 0 {
		if strings.HasPrefix(line, "\\Sample") {
			t.Logf("Expected Error :: %v, %s", line, command.HandleError(errC, errS))
		} else {
			t.Errorf("Error :: %v, %s", line, command.HandleError(errC, errS))
		}
	} else {
		if strings.HasPrefix(line, "\\Sample") {
			t.Errorf("Expected error for command %v. It doesnt exist.", line)
		} else {
			t.Log("Ran command ", line, " successfully.")
			t.Logf("%s", b.String())
		}

	}
	b.Reset()
}
Пример #2
0
func execn1ql(line string, t *testing.T) bool {
	go_n1ql.SetPassthroughMode(true)
	var liner = liner.NewLiner()
	defer liner.Close()

	var b bytes.Buffer
	w := bufio.NewWriter(&b)
	command.SetWriter(w)

	n1ql, err := sql.Open("n1ql", Server)
	if err != nil {
		// If the test cannot connect to a server
		// don't execute the TestExecN1QLStmt method.
		testconn := false
		t.Logf("Cannot connect to %v", Server)
		return testconn
	} else {
		//Successfully logged into the server
		//For the case where server url is valid
		//sql.Open will not throw an error. Hence ping
		//the server and see if it returns an error.

		err = n1ql.Ping()

		if err != nil {
			testconn := false
			t.Logf("Cannot connect to %v", Server)
			return testconn
		}

		errC, errS := ExecN1QLStmt(line, n1ql, w)
		w.Flush()
		if errC != 0 {
			t.Errorf("Error executing statement : %v", line)
			t.Error(command.HandleError(errC, errS))
		} else {
			t.Log("Ran command ", line, " successfully.")
			t.Logf("%s", b.String())
		}
	}
	b.Reset()
	return true
}
Пример #3
0
func execline(line string, t *testing.T) {
	go_n1ql.SetPassthroughMode(true)
	var liner = liner.NewLiner()
	defer liner.Close()

	var b bytes.Buffer
	w := bufio.NewWriter(&b)
	command.SetWriter(w)

	errC, errS := execute_input(line, w, true, liner)
	w.Flush()
	if errC != 0 {
		t.Errorf("Error :: %v, %s", line, command.HandleError(errC, errS))
	} else {
		t.Log("Ran command ", line, " successfully.")
		t.Logf("%s", b.String())
	}
	b.Reset()
}
Пример #4
0
func redirectTo(prevFile, prevreset, prevfgRed string) (string, *os.File) {
	var err error
	var outputFile *os.File

	if command.FILE_RW_MODE == true {
		if prevFile != command.FILE_OUTPUT {
			prevFile = command.FILE_OUTPUT
			outputFile, err = os.OpenFile(command.FILE_OUTPUT, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
			command.SetDispVal("", "")
			if err != nil {
				s_err := command.HandleError(errors.FILE_OPEN, err.Error())
				command.PrintError(s_err)
				return prevFile, nil
			}

		}
	} else {
		command.SetDispVal(prevreset, prevfgRed)
		prevFile = ""
		outputFile = os.Stdout
	}
	return prevFile, outputFile
}
Пример #5
0
/* This method is used to handle user interaction with the
   cli. After combining the multi line input, it is sent to
   the execute_inpu method which parses and executes the
   input command. In the event an error is returned from the
   query execution, it is printed in red. The input prompt is
   the name of the executable.
*/
func HandleInteractiveMode(prompt string) {

	// Variables used for output to file
	var err error
	outputFile := os.Stdout
	prevFile := ""
	prevreset := command.Getreset()
	prevfgRed := command.GetfgRed()

	// If an output flag is defined
	if outputFlag != "" {
		prevFile = command.FILE_OUTPUT
		outputFile, err = os.OpenFile(command.FILE_OUTPUT, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600)
		command.SetDispVal("", "")
		if err != nil {
			s_err := command.HandleError(errors.FILE_OPEN, err.Error())
			command.PrintError(s_err)
		}

		defer outputFile.Close()
		command.SetWriter(io.Writer(outputFile))
	}

	/* Find the HOME environment variable. If it isnt set then
	   try USERPROFILE for windows. If neither is found then
	   the cli cant find the history file to read from.
	*/
	homeDir = os.Getenv("HOME")
	if homeDir == "" {
		homeDir = os.Getenv("USERPROFILE")
		if homeDir == "" {
			_, werr := io.WriteString(command.W, "Unable to determine home directory, history file disabled\n")
			if werr != nil {
				s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
				command.PrintError(s_err)
			}
		}
	}

	/* Create a new liner */
	var liner = liner.NewLiner()
	defer liner.Close()

	/* Load history from Home directory
	 */
	err_code, err_string := LoadHistory(liner, homeDir)
	if err_code != 0 {
		s_err := command.HandleError(err_code, err_string)
		command.PrintError(s_err)
	}

	go signalCatcher(liner)

	// state for reading a multi-line query
	inputLine := []string{}
	fullPrompt := prompt + QRY_PROMPT1

	// Handle the file input and script options here so as to add
	// the commands to the history.
	if scriptFlag != "" {
		//Execute the input command
		go_n1ql.SetPassthroughMode(true)

		// If outputting to a file, then add the statement to the file as well.
		if command.FILE_RW_MODE == true {
			_, werr := io.WriteString(command.W, scriptFlag+"\n")
			if werr != nil {
				s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
				command.PrintError(s_err)
			}
		}

		err_code, err_str := execute_input(scriptFlag, command.W, false, liner)
		if err_code != 0 {
			s_err := command.HandleError(err_code, err_str)
			command.PrintError(s_err)
			liner.Close()
			os.Clearenv()
			os.Exit(1)
		}
		liner.Close()
		os.Clearenv()
		os.Exit(0)
	}

	if inputFlag != "" {
		//Read each line from the file and call execute query
		go_n1ql.SetPassthroughMode(true)
		input_command := "\\source " + inputFlag

		// If outputting to a file, then add the statement to the file as well.
		if command.FILE_RW_MODE == true {
			_, werr := io.WriteString(command.W, input_command+"\n")
			if werr != nil {
				s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
				command.PrintError(s_err)
			}
		}

		errCode, errStr := execute_input(input_command, command.W, false, liner)
		if errCode != 0 {
			s_err := command.HandleError(errCode, errStr)
			command.PrintError(s_err)
			liner.Close()
			os.Clearenv()
			os.Exit(1)
		}
		liner.Close()
		os.Clearenv()
		os.Exit(0)
	}
	// End handling the options

	for {
		line, err := liner.Prompt(fullPrompt)
		if err != nil {
			break
		}

		line = strings.TrimSpace(line)
		if line == "" {
			continue
		}

		// Redirect command
		prevFile, outputFile = redirectTo(prevFile, prevreset, prevfgRed)

		if outputFile == os.Stdout {
			command.SetDispVal(prevreset, prevfgRed)
			command.SetWriter(os.Stdout)
		} else {
			if outputFile != nil {
				defer outputFile.Close()
				command.SetWriter(io.Writer(outputFile))
			}
		}
		/* Check for shell comments : -- and #. Add them to the history
		   but do not send them to be parsed.
		*/
		if strings.HasPrefix(line, "--") || strings.HasPrefix(line, "#") {
			err_code, err_string := UpdateHistory(liner, homeDir, line)
			if err_code != 0 {
				s_err := command.HandleError(err_code, err_string)
				command.PrintError(s_err)
			}

			continue
		}

		// Building query string mode: set prompt, gather current line
		fullPrompt = QRY_PROMPT2
		inputLine = append(inputLine, line)

		/* If the current line ends with a QRY_EOL, join all query lines,
		   trim off trailing QRY_EOL characters, and submit the query string.
		*/
		if strings.HasSuffix(line, QRY_EOL) {
			inputString := strings.Join(inputLine, " ")
			for strings.HasSuffix(inputString, QRY_EOL) {
				inputString = strings.TrimSuffix(inputString, QRY_EOL)
			}
			if inputString != "" {
				err_code, err_string := UpdateHistory(liner, homeDir, inputString+QRY_EOL)
				if err_code != 0 {
					s_err := command.HandleError(err_code, err_string)
					command.PrintError(s_err)
				}
				// If outputting to a file, then add the statement to the file as well.
				if command.FILE_RW_MODE == true {
					_, werr := io.WriteString(command.W, "\n"+inputString+"\n")
					if werr != nil {
						s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
						command.PrintError(s_err)
					}
				}
				err_code, err_string = execute_input(inputString, command.W, true, liner)
				/* Error handling for Shell errors and errors recieved from
				   go_n1ql.
				*/
				if err_code != 0 {
					s_err := command.HandleError(err_code, err_string)
					if err_code == errors.GON1QL_QUERY {
						//Dont print the error code for query errors.
						tmpstr := fmt.Sprintln(command.GetfgRed(), s_err, command.Getreset())
						io.WriteString(command.W, tmpstr+"\n")

					} else {
						command.PrintError(s_err)
					}

					if *errorExitFlag == true {
						if first == false {
							first = true
							_, werr := io.WriteString(command.W, "Exiting on first error encountered\n")
							if werr != nil {
								s_err = command.HandleError(errors.WRITER_OUTPUT, werr.Error())
								command.PrintError(s_err)
							}
							liner.Close()
							os.Clearenv()
							os.Exit(1)
						}
					}
				}

				/* For the \EXIT and \QUIT shell commands we need to
				   make sure that we close the liner and then exit. In
				   the event an error is returned from execute_input after
				   the \EXIT command, then handle the error and exit with
				   exit code 1 (which is for general errors).
				*/
				if EXIT == true {
					command.EXIT = false
					liner.Close()
					if err == nil {
						os.Exit(0)
					} else {
						os.Exit(1)
					}

				}

			}

			// reset state for multi-line query
			inputLine = []string{}
			fullPrompt = prompt + QRY_PROMPT1
		}
	}

}
Пример #6
0
// Helper function to read file based input. Run all the commands as
// seen in the file given by FILE_INPUT and then return the prompt.
func readAndExec(liner *liner.State) (int, string) {
	// Read input file
	inputFile, err := os.Open(command.FILE_INPUT)
	if err != nil {
		return errors.FILE_OPEN, err.Error()
	}

	// Defer file close
	defer inputFile.Close()

	// Create a new reader for the file
	newFileReader := bufio.NewReader(inputFile)

	// Final input command string to be executed
	final_input := " "

	// For redirect command
	outputFile := os.Stdout
	prevFile := ""
	prevreset := command.Getreset()
	prevfgRed := command.GetfgRed()

	// Loop through th file for every line.
	for {

		// Read the line until a new line character. If it contains a ;
		// at the end of the read then that is the query to run. If not
		// keep appending to the string until you reach the ;\n.
		path, err := newFileReader.ReadString('\n')
		if err == io.EOF {
			// Reached end of file. We are done. So break out of the loop.
			break
		} else if err != nil {
			return errors.READ_FILE, err.Error()
		}
		// Remove leading and trailing spaces from the input
		path = strings.TrimSpace(path)
		if strings.HasSuffix(path, ";") {
			// The full input command has been read.
			final_input = final_input + " " + path
		} else {
			// Only part of the command has been read. Hence continue
			// reading until ; is reached.
			final_input = final_input + " " + path
			continue
		}

		// Populate the final string to execute
		final_input = strings.TrimSpace(final_input)

		// Print the query along with printing the
		io.WriteString(command.W, final_input+"\n")

		//Remove the ; before sending the query to execute
		final_input = strings.TrimSuffix(final_input, ";")

		// If outputting to a file, then add the statement to the file as well.
		if command.FILE_RW_MODE == true {
			prevFile, outputFile = redirectTo(prevFile, prevreset, prevfgRed)

			if outputFile == os.Stdout {
				command.SetDispVal(prevreset, prevfgRed)
				command.SetWriter(os.Stdout)
			} else {
				if outputFile != nil {
					defer outputFile.Close()
					command.SetWriter(io.Writer(outputFile))
				}
			}
			io.WriteString(command.W, final_input+"\n")

		}

		errCode, errStr := execute_input(final_input, command.W, false, liner)
		if errCode != 0 {
			s_err := command.HandleError(errCode, errStr)
			command.PrintError(s_err)
		}
		io.WriteString(command.W, "\n\n")
		final_input = " "
	}
	return 0, ""
}
Пример #7
0
/*
This method executes the input command or statement. It
returns an error code and optionally a non empty error message.
*/
func execute_input(line string, w io.Writer, interactive bool, liner *liner.State) (int, string) {
	line = strings.TrimSpace(line)
	command.W = w

	if interactive == false {
		// Check if the line ends with a ;
		line = strings.TrimSpace(line)
		semiC := ""
		if !strings.HasSuffix(line, ";") {
			semiC = ";"
		}
		errCode, errStr := UpdateHistory(liner, homeDir, line+semiC)
		if errCode != 0 {
			s_err := command.HandleError(errCode, errStr)
			command.PrintError(s_err)
		}

	}

	if DISCONNECT == true || NoQueryService == true {
		if strings.HasPrefix(strings.ToLower(line), "\\connect") {
			NoQueryService = false
			command.DISCONNECT = false
			DISCONNECT = false
		}
	}

	// Handle comments here as well. This is useful for the \source
	// command and the --file and --script options.
	if strings.HasPrefix(line, "--") || strings.HasPrefix(line, "#") {
		return 0, ""
	}

	if strings.HasPrefix(line, "\\\\") {
		// This block handles aliases
		commandkey := line[2:]
		commandkey = strings.TrimSpace(commandkey)

		val, ok := command.AliasCommand[commandkey]

		if !ok {
			return errors.NO_SUCH_ALIAS, " : " + commandkey + "\n"
		}

		// If outputting to a file, then add the statement to the file as well.
		if command.FILE_RW_MODE == true {
			_, werr := io.WriteString(command.W, val+"\n")
			if werr != nil {
				return errors.WRITER_OUTPUT, werr.Error()
			}
		}

		err_code, err_str := execute_input(val, w, interactive, liner)
		/* Error handling for Shell errors and errors recieved from
		   go_n1ql.
		*/
		if err_code != 0 {
			return err_code, err_str
		}

	} else if strings.HasPrefix(line, "\\") {
		//This block handles the shell commands
		err_code, err_str := ExecShellCmd(line, liner)
		if err_code != 0 {
			return err_code, err_str
		}

	} else {
		//This block handles N1QL statements
		// If connected to a query service then NoQueryService == false.
		if NoQueryService == true {
			//Not connected to a query service
			return errors.NO_CONNECTION, ""
		} else {
			/* Try opening a connection to the endpoint. If successful, ping.
			   If successful execute the n1ql command. Else try to connect
			   again.
			*/
			n1ql, err := sql.Open("n1ql", ServerFlag)
			if err != nil {
				return errors.GO_N1QL_OPEN, ""
			} else {
				//Successfully logged into the server
				err_code, err_str := ExecN1QLStmt(line, n1ql, w)
				if err_code != 0 {
					return err_code, err_str
				}
			}

		}
	}

	return 0, ""
}
Пример #8
0
func main() {

	flag.Parse()

	if outputFlag != "" {
		// Redirect all output to the given file.
		// This is handled in the HandleInteractiveMode() method
		// in interactive.go.
		command.FILE_RW_MODE = true
		command.FILE_OUTPUT = outputFlag
	}

	// Set command.W = os.Stdout
	command.SetWriter(os.Stdout)

	/* Handle options and what they should do */

	// TODO : Readd ...
	//Taken out so as to connect to both cluster and query service
	//using go_n1ql.
	/*
		if strings.HasPrefix(ServerFlag, "http://") == false {
			ServerFlag = "http://" + ServerFlag
		}

		urlRegex := "^(https?://)[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"
		match, _ := regexp.MatchString(urlRegex, ServerFlag)
		if match == false {
			//TODO Isha : Add error code. Throw invalid url error
			fmt.Println("Invalid url please check" + ServerFlag)
		}


		//-engine
		if strings.HasSuffix(ServerFlag, "/") == false {
			ServerFlag = ServerFlag + "/"
		}
	*/

	/* -version : Display the version of the shell and then exit.
	 */
	if versionFlag == true {
		dummy := []string{}
		cmd := command.Version{}
		cmd.ExecCommand(dummy)
		os.Exit(0)
	}

	/* Check for input url argument
	 */

	args := flag.Args()
	if len(args) > 1 {
		s_err := command.HandleError(errors.CMD_LINE_ARG, "")
		command.PrintError(s_err)
		os.Exit(1)
	} else {
		if len(args) == 1 {
			urlRegex := "^(https?://)[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]"
			match, _ := regexp.MatchString(urlRegex, args[0])
			if match == false {
				s_err := command.HandleError(errors.INVALID_URL, args[0])
				command.PrintError(s_err)
				os.Exit(1)
			} else {
				ServerFlag = args[0]
			}
		}
	}

	/* -quiet : Display Message only if flag not specified
	 */
	if !quietFlag && NoQueryService == false {
		s := fmt.Sprintln("Input connection parameter is " + ServerFlag + ". Type Ctrl-D to exit.\n")
		_, werr := io.WriteString(command.W, s)
		if werr != nil {
			s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
			command.PrintError(s_err)
		}
	}

	/* -user : Accept Admin credentials. Prompt for password and set
	   the n1ql_creds. Append to creds so that user can also define
	   bucket credentials using -credentials if they need to.
	*/
	var creds command.Credentials
	var err error
	var password []byte

	if userFlag != "" {
		//Check if there is a -password option.
		if pwdFlag != "" {
			password = []byte(pwdFlag)
			err = nil
		} else {
			// If no -p option then prompt for the password
			s := fmt.Sprintln("Enter Password: "******"" {
				s_err := command.HandleError(errors.INVALID_PASSWORD, "")
				command.PrintError(s_err)
				os.Exit(1)
			} else {
				creds = append(creds, command.Credential{"user": userFlag, "pass": string(password)})
			}
		} else {
			s_err := command.HandleError(errors.INVALID_PASSWORD, err.Error())
			command.PrintError(s_err)
			os.Exit(1)
		}
	} else {
		// If the -u option isnt specified and the -p option is specified
		// then Invalid Username error.
		if pwdFlag != "" {
			s_err := command.HandleError(errors.INVALID_USERNAME, "")
			command.PrintError(s_err)
			os.Exit(1)
		}
	}

	/* -credentials : Accept credentials to pass to the n1ql endpoint.
	   Ensure that the user inputs credentials in the form a:b.
	   It is important to apend these credentials to those given by
	   -user.
	*/
	if userFlag == "" && credsFlag == "" {
		// No credentials exist. This can still be used to connect to
		// un-authenticated servers.
		// Dont output the statement if we are running in single command
		// mode.
		if scriptFlag == "" {
			_, werr := io.WriteString(command.W, "No Input Credentials. In order to connect to a server with authentication, please provide credentials.\n")

			if werr != nil {
				s_err := command.HandleError(errors.WRITER_OUTPUT, werr.Error())
				command.PrintError(s_err)
			}
		}

	} else if credsFlag != "" {

		creds_ret, err_code, err_string := command.ToCreds(credsFlag)
		if err_code != 0 {
			s_err := command.HandleError(err_code, err_string)
			command.PrintError(s_err)
		}
		for _, v := range creds_ret {
			creds = append(creds, v)
		}

	}
	//Append empty credentials. This is used for cases where one of the buckets
	//is a SASL bucket, and we need to access the other unprotected buckets.
	//CBauth works this way.

	//if credsFlag == "" && userFlag != "" {
	creds = append(creds, command.Credential{"user": "", "pass": ""})
	//}

	/* Add the credentials set by -user and -credentials to the
	   go_n1ql creds parameter.
	*/
	if creds != nil {
		ac, err := json.Marshal(creds)
		if err != nil {
			//Error while Marshalling
			s_err := command.HandleError(errors.JSON_MARSHAL, err.Error())
			command.PrintError(s_err)
			os.Exit(1)
		}
		go_n1ql.SetQueryParams("creds", string(ac))
	}

	if timeoutFlag != "0ms" {
		go_n1ql.SetQueryParams("timeout", timeoutFlag)
	}

	// Handle the inputFlag and ScriptFlag options in HandleInteractiveMode.
	// This is so as to add these to the history.

	go_n1ql.SetPassthroughMode(true)
	HandleInteractiveMode(filepath.Base(os.Args[0]))
}