
org.linkedin.glu.agent.api.Shell.groovy Maven / Gradle / Ivy
/*
* Copyright (c) 2010-2010 LinkedIn, Inc
* Portions Copyright (c) 2011 Yan Pujante
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.linkedin.glu.agent.api
import org.linkedin.util.io.resource.Resource
/**
* Contains shell related methods. Accessible in any script under the variable shell
.
*/
def interface Shell
{
/**
* the root of the file system used by this shell. All files created or returned by
* any methods on this class will be under this root (except for temp files)
*/
Resource getRoot()
/**
* the tmp root of the file system used by this shell. All temp files created will be under
* this root
*/
Resource getTmpRoot()
/**
* Returns a resource relative to this filesystem.
*
* @param file can be of type, java.io.File
,
* org.linkedin.util.io.resource.Resource
, java.net.URI
,
* java.lang.String
(which can be converted into a URI)
*/
Resource toResource(file)
/**
* @param dir starting point for listing ({@see #toResource(Object)} for possible values)
* @param closure the closure (dsl) containing include(name: '') and exclude(name: '') values
* @return an array of {@link Resource}
*/
def ls(dir, Closure closure)
/**
* list all the files under the provided directory (or root if not provided) (not recursive)
* @param dir starting point for listing ({@see #toResource(Object)} for possible values)
* @return an array of {@link Resource}
*/
def ls(dir)
/**
* list all the files under root only (not recursive)
* @return an array of {@link Resource}
*/
def ls()
/**
* Same as the other ls
, but starts at root
* @param closure the closure (dsl) containing include(name: '') and exclude(name: '') values
* @return an array of {@link Resource}
*/
def ls(Closure closure)
/**
* Create the directory as well as its parents if they don't exist
*
* @param dir directory to create ({@see #toResource(Object)} for possible values)
* @return the {@link Resource} representation of the dir
*/
Resource mkdirs(dir)
/**
* Delete the file
*
* @param file ({@see #toResource(Object)} for possible values)
*/
void rm(file)
/**
* Delete the directory (recursive)
*
* @param dir ({@see #toResource(Object)} for possible values)
*/
void rmdirs(dir)
/**
* Remove all empty directories (that are children (recursively) of the provided directory).
* @param dir ({@see #toResource(Object)} for possible values)
*/
void rmEmptyDirs(dir)
/**
* creates a file and populate its content with the provided (String
) content
* @param file ({@see #toResource(Object)} for possible values)
* @param content the content to store in the file
* @return the {@link Resource} representation of the file
*/
Resource saveContent(file, String content)
/**
* reads the content from the file and return it as a String
* @param file ({@see #toResource(Object)} for possible values)
* @return the content
*/
String readContent(file)
/**
* Serializes (java serialization!) the serializable
provided and store in the
* file
* @param file ({@see #toResource(Object)} for possible values)
* @param serializable the object that needs to be serialized
* @return the {@link Resource} representation of the file
*/
Resource serializeToFile(file, serializable)
/**
* Reads the content of the file and deserializes it (java serialization). In order to be
* deserializable, the classpath must contain the classes required.
*
* @param file ({@see #toResource(Object)} for possible values)
* @return whatever was deserialized
*/
def deserializeFromFile(file)
/**
* Safe pattern to write to a file: you provide the file
and the
* closure
gets called back with an {@link java.io.OutputStream} object as an
* argument so you don't have to worry about closing it. Note that the implementation use
* {@link #safeOverwrite(Object, Closure)} under the cover making it safe to overwrite previous
* content.
*
* @param file ({@see #toResource(Object)} for possible values)
* @param closure the callback (takes an {@link java.io.OutputStream} as argument)
* @return whatever the closure returns
*/
def withOutputStream(file, closure)
/**
* Safe pattern to write to a file: you provide the file
and the
* closure
gets called back with an {@link java.io.ObjectOutputStream} object as an
* argument so you don't have to worry about closing it. Note that the implementation use
* {@link #safeOverwrite(Object, Closure)} under the cover making it safe to overwrite previous
* content.
*
* @param file ({@see #toResource(Object)} for possible values)
* @param closure the callback (takes an {@link java.io.ObjectOutputStream} as argument)
* @return whatever the closure returns
*/
def withObjectOutputStream(file, closure)
/**
* Safe pattern to read from a file: you provide the file
and the
* closure
gets called back with an {@link java.io.InputStream} object as an
* argument so you don't have to worry about closing it.
*
* @param file ({@see #toResource(Object)} for possible values)
* @param closure the callback (takes an {@link java.io.InputStream} as argument)
* @return whatever the closure returns
*/
def withInputStream(file, closure)
/**
* Safe pattern to read from a file: you provide the file
and the
* closure
gets called back with an {@link java.io.ObjectInputStream} object as an
* argument so you don't have to worry about closing it.
*
* @param file ({@see #toResource(Object)} for possible values)
* @param closure the callback (takes an {@link java.io.ObjectInputStream} as argument)
* @return whatever the closure returns
*/
def withObjectInputStream(file, closure)
/**
* Changes the permission of the file
*
* @param file ({@see #toResource(Object)} for possible values)
* @param perm expressed in unix fashion (ex: +x)
* @return the {@link Resource} representation of the file
*/
def chmod(file, perm)
/**
* This convenient call takes a file you want to (over)write to and a closure. The closure is
* called back with another resource in the same folder that you can write to and then rename
* the file to the one you wanted. The fact that it is in the same folder ensures that the
* rename should be quick and not really require any copy thus is less likely to fail.
* If the rename fails it throws an exception, thus ensuring that if there was an original
* file it won't be in a partial state.
*
* @param file the final file where you want your output to be ({@see #toResource(Object)} for
* possible values)
* @param closure takes a Resource
as a parameter that you should use
* @return whatever the closure returns
* @throws IOException if cannot rename the file
*/
def safeOverwrite(file, Closure closure) throws IOException
/**
* Every child resource of this resource (recursively) is being passed to the closure. If the
* closure returns true
then it will be part of the result.
* @param dir where to start the recursion ({@see #toResource(Object)} for possible values)
* @param closure will be called back for all children (recursively) as a Resource
* and should return true
or false
* @return the list of all resources where the closure returned true
*/
def findAll(dir, closure)
/**
* Every child resource of this resource (recursively) is being passed to the closure.
*
* @param dir where to start the recursion ({@see #toResource(Object)} for possible values)
* @param closure will be called back for all children (recursively) as a Resource
* and can do whatever it wants with it (return value will be ignored)
* @return the {@link Resource} representation of the dir
*/
Resource eachChildRecurse(dir, closure)
/**
* Copy from to to...
*
* @param from ({@see #toResource(Object)} for possible values)
* @param to ({@see #toResource(Object)} for possible values)
* @return the {@link Resource} representation of to
*/
Resource cp(from, to)
/**
* Move from to to... (rename if file)
*
* @param from ({@see #toResource(Object)} for possible values)
* @param to ({@see #toResource(Object)} for possible values)
* @return the {@link Resource} representation of to
*/
Resource mv(from, to)
/**
* Creates a temp file:
*
* @param args.destdir where the file should be created (optional)
* @param args.prefix a prefix for the file (optional)
* @param args.suffix a suffix for the file (optional)
* @param args.deleteonexit if the temp file should be deleted on exit (default to
* @param args.createParents if the parent directories should be created (default to
* true
)
* @return a file (note that it is just a file object and that the actual file has *not* been
* created and the parents may have been depending on the args.createParents value)
*/
Resource tempFile(args)
/**
* Creates a temp file with all default values
*/
Resource tempFile()
/**
* Create a temporary directory
*/
Resource createTempDir()
/**
* Create a temporary directory
* @see #tempFile(Object) for details on the options
*/
Resource createTempDir(args)
/**
* @return all the environment properties exposed by the glu agent (most are coming from its
* configuration, others are computed (like glu.agent.pid
which is the
* pid of the agent).
*/
Map getEnv()
/**
* Try to guess the mime types of a given file
*
* @param file ({@see #toResource(Object)} for possible values)
* @return a list of mime types (strings)
*/
Collection getMimeTypes(file)
/**
* Unzips the provided file in a temporary location
*
* @param file ({@see #toResource(Object)} for possible values)
* @return the location of the temporary location (as a Resource
)
*/
Resource unzip(file)
/**
* Unzips the provided file in the provided location
*
* @param file ({@see #toResource(Object)} for possible values)
* @param toDir ({@see #toResource(Object)} for possible values)
* @return toDir (as a Resource
)
*/
Resource unzip(file, toDir)
/**
* Untars the provided file in a temporary location. Note that the implementation will try
* to detect if the file is also gziped and unzip it first (equivalent to tar -zxf
)
*
* @param file ({@see #toResource(Object)} for possible values)
* @return the location of the temporary location (as a Resource
)
*/
Resource untar(file)
/**
* Untars the provided file in the provided location. Note that the implementation will try
* to detect if the file is also gziped and unzip it first (equivalent to tar -zxf
)
*
* @param file ({@see #toResource(Object)} for possible values)
* @return toDir (as a Resource
)
*/
Resource untar(file, toDir)
/**
* Gunzips the provided file in a temporary location
*
* @param file ({@see #toResource(Object)} for possible values)
* @return the location of the temporary location (as a Resource
)
*/
Resource gunzip(file)
/**
* Gunzips the provided file in the provided location
*
* @param file ({@see #toResource(Object)} for possible values)
* @param toDir ({@see #toResource(Object)} for possible values)
* @return toDir (as a Resource
)
*/
Resource gunzip(file, toFile)
/**
* Compresses the provided file (in the same folder)
*
* @param file ({@see #toResource(Object)} for possible values)
* @return the gziped file or the original file if not zipped (as a Resource
)
*/
Resource gzip(file)
/**
* Compresses the provided file as toFile
*
* @param file ({@see #toResource(Object)} for possible values)
* @param toFile ({@see #toResource(Object)} for possible values)
* @return toFile (as a Resource
)
*/
Resource gzip(file, toFile)
/**
* Compresses each file in a folder
*
* @param fileOrFolder a file (behaves like {@link #gzip(Object)}) or a folder
* ({@see #toResource(Object)} for possible values)
* @param recurse if true
then recursively process all folders
* @return a map with key is resource and value is delta in size (original - new) (note that it
* contains only the resources that are modified!)
*/
Map gzipFileOrFolder(fileOrFolder, boolean recurse)
/**
* untar + decrypt using the encryption keys (encrytion keys are automatically provided by glu
* and are available in any glu script with args.encriptionKeys
)
*
* @param file ({@see #toResource(Object)} for possible values)
* @param toDir ({@see #toResource(Object)} for possible values)
* @param encryptionKeys
* @return toDir (as a Resource
)
*/
Resource untarAndDecrypt(file, toDir, encryptionKeys)
/**
* Exporting ant access to the shell to run any ant
command.
*
* @return whatever the closure returns
*/
def ant(Closure closure)
/**
* Fetches the file pointed to by the location. If the location is already a {@link File} then
* simply returns it. The location can be a String
or URI
and must
* contain a scheme. Example of locations: http://locahost:8080/file.txt'
,
* file:/tmp/file.txt
, ivy:/org.linkedin/util-core/1.0.0
.
*
* @param location the location you want to fetch (usually remote)
* @return where the location was fetched (locally) (as a Resource
)
*/
Resource fetch(location)
/**
* Fetches the file pointed to by the location. The location can be File
,
* a String
or URI
and must contain a scheme. Example of locations:
* http://locahost:8080/file.txt'
, file:/tmp/file.txt
,
* ivy:/org.linkedin/util-core/1.0.0
. The difference with the other fetch method
* is that it fetches the file in the provided destination rather than in the tmp space.
*
* @param location the location you want to fetch (usually remote)
* @param destination ({@see #toResource(Object)} for possible values)
* @return where the location was fetched (locally) (as a Resource
) (if
* destination
is a file then returns destination
as a
* Resource
otherwise it will be a Resource
inside the
* destination
folder.
*/
Resource fetch(location, destination)
/**
* Returns the content of the location as a String
or
* null
if the location is not reachable
* @param location the location you want to fetch (usually remote)
* @return the content as a Strint
or null
*/
String cat(location)
/**
* Issue a 'HEAD' request. The location should be an http or https link.
*
* @param location
* @return a map with the following entries:
* responseCode: 200, 404... {@link java.net.HttpURLConnection#getResponseCode()}
* responseMessage: message {@link java.net.HttpURLConnection#getResponseMessage()}
* headers: representing all the headers {@link java.net.URLConnection#getHeaderFields()}
*/
Map httpHead(location)
/**
* Issue a 'POST' request. The location should be an http or https link. The request will be
* made with application/x-www-form-urlencoded
content type.
*
* @param location
* @param parameters the parameters of the post as map of key value pairs (value can be a single
* value or a collection of values)
* @return a map with the following entries:
* responseCode: 200, 404... {@link java.net.HttpURLConnection#getResponseCode()}
* responseMessage: message {@link java.net.HttpURLConnection#getResponseMessage()}
* headers: representing all the headers {@link java.net.URLConnection#getHeaderFields()}
*/
Map httpPost(location, Map parameters)
/**
* Similarly to the unix grep command, checks the location one line at a time and returns
* all the lines which matches the pattern.
*
* @param location (see {@link #fetch(Object)} for possible values)
* @param pattern regular expression (see java pattern)
* @return a list of strings
*/
Collection grep(location, pattern)
/**
* Similarly to the unix grep command, checks the location one line at a time and returns
* all the lines which matches the pattern
*
* @param location (see {@link #fetch(Object)} for possible values)
* @param pattern regular expression (see java pattern)
* @param options options to the command:
* out
: an object to output the lines which match (default to [])
* count
: returns the count only (does not use out)
* maxCount
: stop reading after maxCount
matches
* @return depends on options
*/
def grep(location, pattern, options)
/**
* Executes a shell command... the command will be delegated straight to shell and the output of
* the shell command is returned.
*
* @param executable ({@see #toResource(Object)} for possible values)
* @param executableArgs either a String
or a Collection
* @return whatever output the shell command returns
*/
String exec(executable, executableArgs)
/**
* Executes a shell command... the command will be delegated straight to shell and the output of
* the shell command is returned.
*/
/**
* Executes a shell command... the command will be delegated straight to shell and the output of
* the shell command is returned.
*
* @param executable ({@see #toResource(Object)} for possible values)
* @param executableArgs as a vararg of executable args
* @return whatever output the shell command returns
*/
String exec(executable, Object... executableArgs)
/**
* Executes a shell command... the command will be delegated straight to shell and the output of
* the shell command is returned.
*
* @param command the full command (including the arguments) as a String
* @return whatever output the shell command returns
*/
String exec(String command)
/**
* Executes a shell command... the command will be delegated straight to shell and the output of
* the shell command is returned.
*
* @param command the full command (including the arguments) as a Collection
* @return whatever output the shell command returns
*/
String exec(Collection command)
/**
* More generic form of the exec call which allows you to configure what you provide and what you
* expect. This call is blocking (unless you request a stream for the result).
*
* - Note that if you provide a closure for args.stdout
or
* args.stderr
it will be executed in a separate thread (in order to avoid
* blocking indefinitely).
*
* - Note that if you request stdout
, stderr
or
* all
for the result of this call, stdout
and stderr
are
* converted to a String
using (by default) the "UTF-8" charset and all lines
* are terminated with "\n" and the last "\n" is removed. Use stdoutBytes
or
* stderrBytes
if you wish to get the bytes directly
*
* - Note that if you request stream
, then the call return immediately
* (it is non blocking in this case) and you get a single InputStream
* which multiplexes stdout/stderr and exit value (see MultiplexedInputStream
for
* details). In this case you should make sure to read the entire stream and properly close it
* as shown in the following code example:
*
* InputStream stream = shell.exec(command: 'xxx', res: 'stream')
* try
* {
* // read stream
* }
* finally
* {
* stream.close()
* }
*
* - Note that if you request stdoutStream
or stderrStream
, then the
* call return immediately (it is non blocking in this case) and you get the stream you requested.
* In this case you should make sure to read the entire stream and properly close it as
* shown in the following code example:
*
* InputStream stream = shell.exec(command: 'xxx', res: 'stdoutStream')
* try
* {
* // read stream
* }
* finally
* {
* stream.close()
* }
*
*
* @param args.command the command to execute. It will be delegated to the shell so it should
* be native to the OS on which the agent runs (either a String
* or a Collection
) (required)
* @param args.pwd the directory from which the command will be run (optional, will
* default to the "current" directory)
* @param args.env a map (String
, String
) containing environment
* variables to be passed to sub-process. If the value is null
,
* it will remove it from the inherited environment variables. (optional)
* @param args.inheritEnv a boolean to determine if the environment variables in effect in the
* agent will be passed down to the sub-process (optional, default to
* true
)
* @param args.stdin any input that can "reasonably" be converted into an
* InputStream
) to provide to the command line execution
* (optional, default to no stdin)
* @param args.stdout Closure
(if you want to handle it yourself),
* OutputStream
(where stdout will be written to),
* (optional: depends on args.res)
* @param args.stderr Closure
(if you want to handle it yourself),
* OutputStream
(where stdout will be written to),
* (optional: depends on args.res)
* @param args.redirectStderr boolean
to redirect stderr into stdout
* (optional, default to false
). Note that this can also
* be accomplished with the command itself with something like "2>&1"
* @param args.failOnError do you want the command to fail (with an exception) when there is
* an error (default to true
)
* @param args.res what do you want the call to return
* stdout
, stdoutBytes
, stdoutStream
* stderr
, stderrBytes
, stderrStream
* all
, allBytes
(a map with 3 parameters, exitValue, stdout, stderr)
* exitValue
,
* stream
* (default to stdout
)
* @return whatever is specified in args.res
*/
def exec(Map args)
/**
* Demultiplexes the exec stream as generated by {@link #exec(Map)} when args.res
is
* stream
. The following is equivalent:
*
* OutputStream myStdout = ...
* OutputStream myStderr = ...
*
* exec(command: xxx, stdout: myStdout, stderr: myStderr, res: exitValue)
*
* is 100% equivalent to:
*
* demultiplexExecStream(exec(command: xxx, res: stream), myStdout, myStderr)
*
* @param execStream the stream as generated by {@link #exec(Map)}
* @param stdout the stream to write the output (optional, can be null
)
* @param stderr the stream to write the error (optional, can be null
)
* @return the value returned by the executed subprocess
* @throws org.linkedin.glu.agent.api.ShellExecException when there was an error executing the
* shell script and args.failOnError
was set to true
*/
def demultiplexExecStream(InputStream execStream,
OutputStream stdout,
OutputStream stderr)
/**
* Shortcut/More efficient implementation of the more generic {@link #chmod(Object, Object)} call
*
* @param file ({@see #toResource(Object)} for possible values)
* @return file as a Resource
*/
Resource chmodPlusX(file)
/**
* Changes the permission of the dir
and recursively
*
* @param dir ({@see #toResource(Object)} for possible values)
* @param perm expressed in unix fashion (ex: +x)
* @return the {@link Resource} representation of the dir
*/
Resource chmodRecursive(dir, perm)
/**
* Invokes the closure with an MBeanServerConnection
to the jmx control running
* on the vm started with the provided pid. The closure will be invoked with null
* if cannot determine the process.
*
* @param pid the pid of the process you want to get an mbean connection
* @param closure will be called back with a MBeanServerConnection
(which will be
* null
if cannot connect)
* @return whatever the closure returns
*/
def withMBeanServerConnection(pid, Closure closure)
/**
* Waits for the condition to be true
no longer than the timeout. true
* is returned if the condition was satisfied, false
otherwise (if you specify
* noException)
* @param args.timeout how long max to wait (any value convertible to a Timespan
)
* @param args.heartbeat how long to wait between calling the condition (any value convertible to
* a Timespan
)
* @param args.noException to get false
instead of an exception
* @param condition the closure should return true
if the condition is satisfied,
* false
otherwise
* @return true
if condition was satisfied within the timeout, false
* otherwise (if args.noException is provided
otherwise an exception will
* be raised)
*/
boolean waitFor(args, Closure condition)
/**
* Shortcut when no args
* @see #waitFor(Object, Closure)
*/
boolean waitFor(Closure condition)
/**
* Tail the file
*
* @params file the file to tail ({@see #toResource(Object)} for possible values)
* @params maxLine the number of lines maximum to read
*
* @return the input stream to read the content of the tail
*/
InputStream tail(file, long maxLine)
/**
* Tail the file
*
* @params args.location the location of the file to tail ({@see #toResource(Object)} for possible values)
* @params args.maxLine the number of lines maximum to read (-1 for the entire file)
* @params args.maxSize the maximum size to read (-1 for the entire file)
*
* @return the input stream to read the content of the tail
*/
InputStream tail(args)
/**
* @return true
if there is a socket open on the server/port combination
*/
boolean listening(server, port)
/**
* Replaces the tokens provided in the map in the input. Token replacement is using ant token
* replacement class so in the input, the tokens are surrounded by the '@' sign.
* Example:
*
*
* input = "abcd @myToken@"
* assert "abcd foo" == replaceTokens(input, [myToken: 'foo'])
*
*/
String replaceTokens(String input, Map tokens)
/**
* Processes from
through the replacement token mechanism and writes the result to
* to
*
* @param from ({@see #toResource(Object)} for possible values)
* @param to ({@see #toResource(Object)} for possible values)}
* @param tokens a map of token
* @return to
as a {@link Resource}
* @see #replaceTokens(String, Map)
*/
Resource replaceTokens(def from, def to, Map tokens)
/**
* Processes the content to the token replacement method.
*
* @see #saveContent(Object, String)
*/
Resource saveContent(file, String content, Map tokens)
/**
* Same as withInputStream
but wraps in a reader using a configured charset (defaults
* to UTF-8).
*
* @param file ({@see #toResource(Object)} for possible values)
* @return whatever the closure returns
*/
def withReader(file, Closure closure)
/**
* Same as withOutputStream
but wraps in a writer using a configured charset (defaults
* to UTF-8).
*
* @param file ({@see #toResource(Object)} for possible values)
* @return whatever the closure returns
*/
def withWriter(file, Closure closure)
/**
* Runs the closure in a protected block that will not throw an exception but will return
* null
in the case one happens
*
* @return whatever the closure returns unless there is an exception in which case it will
* return null
(and log the exception as a debug message)
*/
def noException(Closure closure)
/**
* Calling this method will force a script failure (will throw an exception)
*/
void fail(message)
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy