Filtering tab completion in input task implementation - sbt

I'm currently implementing a SBT plugin for Gatling.
One of its features will be to open the last generated report in a new browser tab from SBT.
As each run can have a different "simulation ID" (basically a simple string), I'd like to offer tab completion on simulation ids.
An example :
Running the Gatling SBT plugin will produce several folders (named from simulationId + date of report generaation) in target/gatling, for example mysim-20140204234534, myothersim-20140203124534 and yetanothersim-20140204234534.
Let's call the task lastReport.
If someone start typing lastReport my, I'd like to filter out tab-completion to only suggest mysim and myothersim.
Getting the simulation ID is a breeze, but how can help the parser and filter out suggestions so that it only suggest an existing simulation ID ?
To sum up, I'd like to do what testOnly do, in a way : I only want to suggest things that make sense in my context.
Thanks in advance for your answers,
Pierre
Edit : As I got a bit stuck after my latest tries, here is the code of my inputTask, in it's current state :
package io.gatling.sbt
import sbt._
import sbt.complete.{ DefaultParsers, Parser }
import io.gatling.sbt.Utils._
object GatlingTasks {
val lastReport = inputKey[Unit]("Open last report in browser")
val allSimulationIds = taskKey[Set[String]]("List of simulation ids found in reports folder")
val allReports = taskKey[List[Report]]("List of all reports by simulation id and timestamp")
def findAllReports(reportsFolder: File): List[Report] = {
val allDirectories = (reportsFolder ** DirectoryFilter.&&(new PatternFilter(reportFolderRegex.pattern))).get
allDirectories.map(file => (file, reportFolderRegex.findFirstMatchIn(file.getPath).get)).map {
case (file, regexMatch) => Report(file, regexMatch.group(1), regexMatch.group(2))
}.toList
}
def findAllSimulationIds(allReports: Seq[Report]): Set[String] = allReports.map(_.simulationId).distinct.toSet
def openLastReport(allReports: List[Report], allSimulationIds: Set[String]): Unit = {
def simulationIdParser(allSimulationIds: Set[String]): Parser[Option[String]] =
DefaultParsers.ID.examples(allSimulationIds, check = true).?
def filterReportsIfSimulationIdSelected(allReports: List[Report], simulationId: Option[String]): List[Report] =
simulationId match {
case Some(id) => allReports.filter(_.simulationId == id)
case None => allReports
}
Def.inputTaskDyn {
val selectedSimulationId = simulationIdParser(allSimulationIds).parsed
val filteredReports = filterReportsIfSimulationIdSelected(allReports, selectedSimulationId)
val reportsSortedByDate = filteredReports.sorted.map(_.path)
Def.task(reportsSortedByDate.headOption.foreach(file => openInBrowser((file / "index.html").toURI)))
}
}
}
Of course, openReport is called using the results of allReports and allSimulationIds tasks.
I think I'm close to a functioning input task but I'm still missing something...

Def.inputTaskDyn returns a value of type InputTask[T] and doesn't perform any side effects. The result needs to be bound to an InputKey, like lastReport. The return type of openLastReport is Unit, which means that openLastReport will construct a value that will be discarded, effectively doing nothing useful. Instead, have:
def openLastReport(...): InputTask[...] = ...
lastReport := openLastReport(...).evaluated
(Or, the implementation of openLastReport can be inlined into the right hand side of :=)
You probably don't need inputTaskDyn, but just inputTask. You only need inputTaskDyn if you need to return a task. Otherwise, use inputTask and drop the Def.task.

Related

How to make this function where I can give it an argument or not

So I made this very small function. it is a bonehead easy function but frankly borderline my capabilities.. Im learning. The function works as expected, but I would like to go further. I would like to make it so I can either give it an argument (a username) and just get the information for that single user, or default to reporting all users. is this possible w/o starting over from what I have so far?
I have just poked around and seen some examples but nothing that I can fit into my script. that I can understand at least.
import boto3
iam = boto3.client('iam')
def user_group():
for myusers in iam.list_users()['Users']:
Group = iam.list_groups_for_user(UserName=myusers['UserName'])
print("User: " + myusers['UserName'])
for groupName in Group['Groups']:
print("Group: " + groupName['GroupName'])
print("----------------------------")
user_group()
I would like to have the ability to run this script in two fashions.
1) add an argument(s) of 'username' so I can get the response for a particular user
2) default to getting response for all users if no argument is given.
This can be done by using an argument with a default value:
def user_group(user = None):
if user is None:
print("No user")
else:
print(user)
user_group()
user_group('some user')
prints
No user
some user
In your case you may want to write
def user_group(user = None):
users_to_list = iam.list_users()['Users'] if user is None else [user]
for myusers in user_to_list:
...

Difference between two files view in HTML using Java or any jar

I want to write a script which compare two files in java and see there difference in html page ( side by side ), can someone help me out how to write ( where to start). I am pulling my hair out for this....
I want to use this script in beanshell postprocessor so that I can compare the standard output files with result files easily
I don't think you should be asking people for writing code for you here, consider hiring a freelancer instead.
Alternatively you can use the following approach:
Add JSR223 Assertion as a child of the request which you would like to fail if files won't be equal
Put the following code into "Script" area:
def file1 = new File('/path/to/file1')
def file2 = new File('/path/to/file2')
def file1Lines = file1.readLines('UTF-8')
def file2Lines = file2.readLines('UTF-8')
if (file1Lines.size() != file2Lines.size()) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage('Files size is different, omitting line-by-line compare')
} else {
def differences = new StringBuilder()
file1Lines.eachWithIndex {
String file1Line, int number ->
String file2Line = file2Lines.get(number)
if (!file1Line.equals(file2Line)) {
differences.append('Difference # ').append(number).append('. Expected: ')
.append(file1Line).append('. Actual: ' + file2Line)
differences.append(System.getProperty('line.separator'))
}
}
if (differences.toString().length() > 0) {
AssertionResult.setFailure(true)
AssertionResult.setFailureMessage(differences.toString())
}
}
If there will be differences in files content you will see them listed one by one in the JSR223 Assertion
See Scripting JMeter Assertions in Groovy - A Tutorial for more details.

Convert Time.now to Date - Elm

Hello I am brand new to Elm and I am having some difficulty with getting the current time and converting it into a date in Elm.
I have a message type - Message and a function to add a new message to the model. I am trying to store the time the message was posted along with the text and user id.
However I keep getting this error -
The argument to function `fromTime` is causing a mismatch.
59| Date.fromTime (currentTime Time.now)
^^^^^^^^^^^^^^^^^^^^
Function `fromTime` is expecting the argument to be:
Time
But it is:
x -> Time -> Time
Hint: It looks like a function needs 2 more arguments.
Here is the code
type alias Message =
{ text : String,
date : Date,
userId : Int
}
currentTime : task -> x -> Time -> Time
currentTime _ _ time =
time
newMessage : String -> Int -> Message
newMessage message id =
{ text = message
, date = Date.fromTime (currentTime Time.now)
, userId = id
}
I really can't figure out what is going on. Any help would be much appreciated. Thanks.
Elm is a pure language, where function calls are deterministic. Requesting the current time is a little more complex, because there is no function we can call that will return us a different time depending on the time of day. Function calls with the same input will always return the same thing.
Getting the current time lies in the land of side effects. We have to ask the architecture to give us the time in a way that is pure. The way Elm deals with that is through the Task and Program functionality. You send a Task to the Elm Architecture through a Cmd in your update function. The Elm Architecture then does its own thing behind the scenes to fetch the current time, then it responds in pure code with another call to your update function.
Here is a simple example you can paste in at http://elm-lang.org/try, where you click a button to see the current time converted to a Date.
import Html exposing (..)
import Html.Events exposing (onClick)
import Time exposing (..)
import Date
import Task
main =
Html.program
{ init = { message = "Click the button to see the time" } ! []
, view = view
, update = update
, subscriptions = \_ -> Sub.none
}
type alias Model = { message: String }
view model =
div []
[ button [ onClick FetchTime ] [ text "Fetch the current time" ]
, div [] [ text model.message ]
]
type Msg
= FetchTime
| Now Time
update msg model =
case msg of
FetchTime ->
model ! [ Task.perform Now Time.now ]
Now t ->
{ model | message = "The date is now " ++ (toString (Date.fromTime t)) } ! []
If you are familiar with javascript, the purpose of the Now message could be loosely thought of as a callback function, where the argument it provides is the time sent by the Elm Architecture.

How to access #1 inside conditional inside array->forEach

I trying to learn captures in Lasso 9, but I am struggling to figure out how to access the #1 local variable from within a conditional that's inside an array->forEach capture. Maybe my approach is all wrong. Is there a reference to the parent capture that I need to use? Following is the working code:
define paramstovars() => {
local(p = web_request->params)
#p->foreach => {
local(i = #1)
if(#i->type == 'pair') => {
var(#i->first->asstring = #i->second->asstring)
}
}
}
Following is the code I am trying to get working without relying on a redundant local variable definition:
define paramstovars() => {
local(p = web_request->params)
#p->foreach => {
if(#1->type == 'pair') => {
var(#1->first->asstring = #1->second->asstring)
}
}
}
In this second example, I receive an error that Position was out of range: 1 max is 0 (Error Code -1) on the line calling var().
Obvious security concerns with this custom method aside, what's the most efficient way to make #1 available inside nested conditionals?
#1 is replaced within each capture — so yes, you will need to assign it to another local in order to use it in deeper captures. If you need to work with the local again try using query expressions instead:
with i in web_request->params do {
if(#i->type == 'pair') => {
var(#i->first->asstring = #i->second->asstring)
}
}
Also, I wouldn't recommend settings variables in this fashion — it posses a security risk. It would be better to store the parameters in a single variable and then potentially set specific variables from that. There's a set of tags that does something similar here: getparam / postparam
It is my experience that #1 is consumed when called first time. At least I have never ben able to call it twice in the same capture.
If I need the value more than once I make it a local first. As you do in your example 1.
Some experiments later.
You can call #1 several times, contrary to what I wrote, but what trips your effort is that you have a capture inside the capture (the conditional).
The second capture will have it's own input params.
Here's a working, tested example to do what you want to do:
local(
myarray = array(1, 2 = 'two', 3 = 'four', 4),
mypairs = map
)
#myarray -> foreach => {
if(#1-> isa(::pair)) => {
#mypairs -> insert(#1 -> first -> asstring = #1 -> second -> asstring)
}(#1)
}
#my pairs
The result will be map(2 = two, 3 = four)
The trick is the sending of the foreach param to the conditional capture : `{some code}(#1)
Now, with all that worked out. I recommend that you take a look at Ke Carltons latest addition to tagswap. It will solve the same problem way better than creating a bunch of dynamic vars as you are attempting to do:
www.lassosoft.com/tagswap/detail/web_request_params

Transform bag of key-value tuples to map in Apache Pig

I am new to Pig and I want to convert a bag of tuples to a map with specific value in each tuple as key. Basically I want to change:
{(id1, value1),(id2, value2), ...} into [id1#value1, id2#value2]
I've been looking around online for a while, but I can't seem to find a solution. I've tried:
bigQMap = FOREACH bigQFields GENERATE TOMAP(queryId, queryStart);
but I end up with a bag of maps (e.g. {[id1#value1], [id2#value2], ...}), which is not what I want. How can I build up a map out of a bag of key-value tuple?
Below is the specific script I'm trying to run, in case it's relevant
rawlines = LOAD '...' USING PigStorage('`');
bigQFields = FOREACH bigQLogs GENERATE GFV(*,'queryId')
as queryId, GFV(*, 'queryStart')
as queryStart;
bigQMap = ?? how to make a map with queryId as key and queryStart as value ?? ;
TOMAP takes a series of pairs and converts them into the map, so it is meant to be used like:
-- Schema: A:{foo:chararray, bar:int, bing:chararray, bang:int}
-- Data: (John, 27, Joe, 30)
B = FOREACH A GENERATE TOMAP(foo, bar, bing, bang) AS m ;
-- Schema: B:{m: map[]}
-- Data: (John#27,Joe#30)
So as you can see the syntax does not support converting a bag to a map. As far as I know there is no way to convert a bag in the format you have to map in pure pig. However, you can definitively write a java UDF to do this.
NOTE: I'm not too experienced with java, so this UDF can easily be improved on (adding exception handling, what happens if a key added twice etc.). However, it does accomplish what you need it to.
package myudfs;
import java.io.IOException;
import org.apache.pig.EvalFunc;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import org.apache.pig.data.Tuple;
import org.apache.pig.data.DataBag;
public class ConvertToMap extends EvalFunc<Map>
{
public Map exec(Tuple input) throws IOException {
DataBag values = (DataBag)input.get(0);
Map<Object, Object> m = new HashMap<Object, Object>();
for (Iterator<Tuple> it = values.iterator(); it.hasNext();) {
Tuple t = it.next();
m.put(t.get(0), t.get(1));
}
return m;
}
}
Once you compile the script into a jar, it can be used like:
REGISTER myudfs.jar ;
-- A is loading some sample data I made
A = LOAD 'foo.in' AS (foo:{T:(id:chararray, value:chararray)}) ;
B = FOREACH A GENERATE myudfs.ConvertToMap(foo) AS bar;
Contents of foo.in:
{(open,apache),(apache,hadoop)}
{(foo,bar),(bar,foo),(open,what)}
Output from B:
([open#apache,apache#hadoop])
([bar#foo,open#what,foo#bar])
Another approach is to use python to create the UDF:
myudfs.py
#!/usr/bin/python
#outputSchema("foo:map[]")
def BagtoMap(bag):
d = {}
for key, value in bag:
d[key] = value
return d
Which is used like this:
Register 'myudfs.py' using jython as myfuncs;
-- A is still just loading some of my test data
A = LOAD 'foo.in' AS (foo:{T:(key:chararray, value:chararray)}) ;
B = FOREACH A GENERATE myfuncs.BagtoMap(foo) ;
And produces the same output as the Java UDF.
BONUS:
Since I don't like maps very much, here is a link explaining how the functionality of a map can be replicated with just key value pairs. Since your key value pairs are in a bag, you'll need to do the map-like operations in a nested FOREACH:
-- A is a schema that contains kv_pairs, a bag in the form {(id, value)}
B = FOREACH A {
temp = FOREACH kv_pairs GENERATE (key=='foo'?value:NULL) ;
-- Output is like: ({(),(thevalue),(),()})
-- MAX will pull the maximum value from the filtered bag, which is
-- value (the chararray) if the key matched. Otherwise it will return NULL.
GENERATE MAX(temp) as kv_pairs_filtered ;
}
I ran into the same situation so I submitted a patch that just got accepted: https://issues.apache.org/jira/browse/PIG-4638
This means that what you wanted is a core part starting with pig 0.16.

Resources