ducttape: sometimes skip task: branch on multiple variables - ducttape

Related to this question: ducttape sometimes-skip task: cross-product error
Say I have a plan like this:
task map_lexicon
< in_lexicon=$pron_lex
> out_lexicon=lex
> out_w2p=lex.w2p
> out_p2w=lex.p2w
{
cp $in_lexicon $out_lexicon
echo "" > $out_w2p
echo "" > $out_p2w
}
task prune_lexicon
# Prunes a lexicon
< in_lexicon=$pron_lex
> out_lex_pruned=lex.pruned
> out_w2p_pruned=lex.w2p.pruned
> out_p2w_pruned=lex.p2w.pruned
{
cp $in_lexicon $out_lex_pruned
echo "" > $out_w2p_pruned
echo "" > $out_p2w_pruned
}
global {
lex1=/path/to/foo
pron_lex=(PronLex: Lex1=$lex1)
}
Further down the pipeline, I want to create a branch that takes map_lexicon or prune_lexicon as a dependency. However, each task has 3 outputs that I need to use. Example:
global {
lex_type=(LexType: raw=$out_lexicon#map_lexicon pruned=$out_lex_pruned#prune_lexicon)
}
task foo
< in_lex=$in_lex#map_lexicon
< in_w2p=$out_w2p#map_lexicon
< in_p2w=$out_p2w#map_lexicon
> bar
{
echo $in_lex $in_w2p $in_p2w > bar
}
Is there a way to set up a sometimes-skip task to manage three variables within a single branch point?

Turns out all that's necessary is to define the additional variables with the same branch points.
global {
lex=(LexType: raw=$out_lexicon#map_lexicon pruned=$out_lex_pruned#prune_lexicon)
w2p=(LexType: raw=$out_w2p#map_lexicon pruned=$out_w2p_pruned#prune_lexicon)
p2w=(LexType: raw=$out_p2w#map_lexicon pruned=$out_p2w_pruned#prune_lexicon)
}
Then define foo as:
task foo
< in_lex=$lex
< in_w2p=$w2p
< in_p2w=$p2w
> bar
{
echo $in_lex $in_w2p $in_p2w > bar
}

Related

Getting reference to shared data in async closure [duplicate]

I have something like this:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
move || { arc.clone() };
move || { arc.clone() };
}
I am getting:
error[E0382]: capture of moved value: `arc`
--> src/main.rs:6:19
|
5 | move || { arc.clone() };
| ------- value moved (into closure) here
6 | move || { arc.clone() };
| ^^^ value captured here after move
|
= note: move occurs because `arc` has type `std::sync::Arc<i32>`, which does not implement the `Copy` trait
I understand why I am getting this: the clone isn't called before arc is passed to the closure. I can fix this by defining each closure in a function and clone the Arc before passing it to the closure, but is there another option?
There is no way around it. You should clone the Arc before it is used in a closure. The common pattern is to re-bind the cloned Arc to the same name in a nested scope:
use std::sync::Arc;
fn main() {
let arc = Arc::new(42);
{
let arc = arc.clone();
move || { /* do something with arc */ };
}
{
let arc = arc.clone();
move || { /* do something else with arc */ };
}
}
This is usually done together with thread::spawn():
use std::sync::{Arc, Mutex};
use std::thread;
const NUM_THREADS: usize = 4;
fn main() {
let arc = Arc::new(Mutex::new(42));
for _ in 0..NUM_THREADS {
let arc = arc.clone();
thread::spawn(move || {
let mut shared_data = arc.lock().unwrap();
*shared_data += 1;
});
}
}
is there another option?
Because this pattern of cloning things before defining a closure is somewhat common, some people have proposed adding something like clone || as an analog to move ||. I wouldn't hold out hope for this happening, but a number of comments there point out that macros can solve the case fairly well.
Several crates provide some form of this macro:
closet
capture
clone_all
It's likely that many projects define their own macro to do something similar. For example, the WASM example rust-todomvc defines:
macro_rules! enclose {
( ($( $x:ident ),*) $y:expr ) => {
{
$(let $x = $x.clone();)*
$y
}
};
}
Which can be used as:
fn main() {
let arc = Arc::new(42);
enclose! { (arc) move || arc };
enclose! { (arc) move || arc };
}

Comparing of list's elements downloaded by WebDriver

I need to compare elements from tables which are presented on a few subpages (only values from first column).
Using lists I created one big list (which has ex. 95 elements). Unfortunately when I start comparing them, my test end with an error message "org.openqa.selenium.StaleElementReferenceException: stale element reference: element is not attached to the page document"
Everything works correctly when I have less than 10 elements (only one table on one page).
Do someone know what should I change in my code?
List<WebElement> pagesList = webDriver.findElements(By.cssSelector("#div_table > ul > li"));
if (pagesList.size() > 0) {
boolean nextPagePresent = true;
List<String> documentsList = webDriver.findElements(By.cssSelector("#table > tbody > tr > td:nth-child(1)"));
while (nextPagePresent == true) {
try {
nextPagePresent = webDriver.findElements(By.cssSelector("#div_table > ul > li.nextLink")).size() > 0;
documentsList += webDriver.findElements(By.cssSelector("#table > tbody > tr > td:nth-child(1)"));
if(nextPagePresent == true) {
webDriver.findElement(By.cssSelector("#div_table > ul > li.nextLink")).click();
}
} catch (org.openqa.selenium.NoSuchElementException ex) {
throw new Exception('Page not found');
}
}
documentsList.removeRange(0, 10);
for (int i = 0; i < documentsList.size(); i++) {
for (int k = i + 1; k < documentsList.size(); k++) {
if (documentsList.get(i).getText().equals(documentsList.get(k).getText())) {
log.info(documentsList.get(i).getText())
assert false;
}
}
}
} else {
List<String> documentsList = webDriver.findElements(By.cssSelector("#table > tbody > tr > td:nth-child(1)"));
for (int i = 0; i < documentsList.size(); i++) {
for (int k = i + 1; k < documentsList.size(); k++) {
if (documentsList.get(i).getText().equals(documentsList.get(k).getText())) {
assert false;
}
}
}
}
The exception you're seeing is expected since you have elements located on multiple pages and you're actually switching between them.
Basically the exception you're getting indicates that, i.e. it says it is unable to retrieve text from WebElement, which is logically correct since the element is no longer attached to the DOM model.
What you could do is to extract text from elements that are currently visible on the page and put it into separate List<String>, once you'll extract text from all the elements from all the pages you could compare it.
So order of actions should look like this:
Load page
Extract text from all visible elements and put it into separate list
Change page
Repeat steps 2,3 until there are no pages left
Compare results
More detailed info on exception could be found here: https://www.seleniumhq.org/exceptions/stale_element_reference.jsp
P.S. Usage of build-in asserts should be avoided, consider using test java test libraries like jUnit or TestNg or assert specific libraries like assert4j it would give you more flexibility.

Puppet advanced default params

Basically I have a puppet class cassandra_manager::params. I have a ton of params set like so:
# etc...
$cluster_name = undef,
$num_tokens = 256,
$initial_token = undef,
$hinted_handoff_enabled = true,
# etc...
Now most of these ones set undef, I just handle in my template just commenting it out if it's undef.
But there are a few that I need to use some previous params, and facts to figure out the defaults. Here is one main example:
$memtable_flush_writers = undef,
I then try to set it later like this:
$min_from_cores_and_disks = min([ $::processorcount, size(split($::hard_drives, ',')) ])
if !$memtable_flush_writers {
if 0 + (0 + $min_from_cores_and_disks[0]) > 8 or (0 + $min_from_cores_and_disks[0]) < 2 {
if (0 + $min_from_cores_and_disks[0]) < 2 {
$memtable_flush_writers = 2
}
elsif (0 + $min_from_cores_and_disks[0]) > 8 {
$memtable_flush_writers = 8
}
} else {
$memtable_flush_writers = (0 + $min_from_cores_and_disks[0])
}
}
Then puppet tells me I can't set $memtable_flush_writers because all variables are immutable in puppet.
So then I changed checking for whether the variable was "false" and didn't set the variable up above, but that just told me the obvious, that $memtable_flush_writers wasn't set.
What's the best way that I can still get the functionality from the if statements above without having these errors pop up. Thanks in advance.
You have to create a new variable which you use only for declaration and setting any default value in the class definition.
class cassandra_manager::params (
$memtable_flush_writers_count = undef
){
if !$memtable_flush_writers_count {
# Whatever you want to do
$memtable_flush_writers = 'your_value'
} else {
$memtable_flush_writers = $memtable_flus_writers_count
}
}
The variables in cassandra_manager::params are typically used as default values for parameters of class cassandra_manager.
class cassandra_manager(
$cluster_name = $cassandra_manager::params::cluster_name,
$num_tokens = $cassandra_manager::params::num_tokens,
...) inherits cassandra_manager::params {
}
You override the defaults by passing such parameters.
class {
'cassandra_manager':
memtable_flush_writers => <value for this node>
}

Change FS definition past the header of a CSV file

I got this kind of CSV file:
name,x-extension,value,extra
"Roger","9890","",""
"Nicole","9811","president, ceo",""
...
Now, I want the find the maximum size of each field in the file. So I used this awk script:
Updated script:
NR==1 {
gsub(/\r/,"",$0) #remove linefeed from last field name
for (n = 1; n <= NF; n++) {
colname[n]=$n;
maxlen[n]=-1;
}
nbrField = NF; # will get bump +2 by the new FS
FS="\",\"|^\"|\"$";
}
NR>1 {
for (n = 2; n <= nbrField+1; n++) {
if (length($n)>maxlen[n-1]) {
maxlen[n-1]=length($n);
}
}
}
END {
for(i = 1; i <= nbrField; i++) {
printf "%s : %s\n", colname[i], maxlen[i]
}
}
The problem a got is I need to change the field separator AFTER reading the first line because as you can see, the header don't use double quote for field delimiter and there is coma INSIDE some field.
I tried to play with this -F option on my awk command line but I can't find the right combination of regex to do the trick..
> awk -F'", "|^"|"$' -f myprog mydata ==>(don't work)
Help! :-)
Change FS in the block that processes the first line:
NR==1 {
for(n = 1; n <= NF; n++) {
colname[n]=$n
}
FS="\",\"|^\"|\"$"
}
I prefer to use a real CSV parser for CSV data. For example, Perl:
perl -MText::CSV -MList::Util=max -nE '
BEGIN {$csv = Text::CSV->new({binary=>1})}
$csv->parse($_);
#row = $csv->fields();
if ($. == 1) {
#h = #row; $n = $#row;
}
else {
$max{$h[$_]} = max($max{$h[$_]}, length $row[$_]) for (0..$n)
}
END {
while (($k,$v) = each %max) {say join ":", $k, $v}
}
' << DATA
name,x-extension,value,extra
"Roger","9890","",""
"Nicole","9811","president, ceo",""
DATA
value:14
name:6
extra:0
x-extension:4

Parsing digits from command line argv

I want to change a perl script that executes a loop some times, and I want to pass the number of loops by command line option. The program now receives some options, then I need to change it to receive a new parameter, but it is the first time I see a perl script, then I don't know how to change.
The start of program (to parse command line options) is:
if ($#ARGV >= 1) {
for ($i = 1; $i <= $#ARGV; $i++) {
if ($ARGV[$i] =~ /^\-/) {
if ($ARGV[$i] =~ /\-test/) {
//do something
}
} else {
//do something other
}
}
}
I think that I must put something like:
if ($ARGV[$i] =~ /^\-L40/)
But it only match to 40, I don't know how to parse the number attached to the -L parameter to use for the loop limit.
Thanks in advance and sorry if there is any similar question, but I don't find any.
use Getopt::Long qw( );
sub usage {
print(STDERR "usage: prog [--test] [-L NUM]\n");
exit(1);
}
GetOptions(
'test' => \my $opt_test,
'L=i' => \my $opt_L,
)
or usage();
die("-L must be followed by a positive integer\n")
if defined($opt_L) && $opt_L < 1;
Something like:
my $loopLimit = 1; # default
if ($#ARGV >= 1)
{
for ($i = 1; $i <= $#ARGV; $i++)
{
if ($ARGV[$i] =~ /^\-/)
{
if ($ARGV[$i] =~ /\-test/)
{
# do something
}
elsif ($ARGV[$i] =~ /\-L(\d+)/) # -L followed by digits
{
$loopLimit = $1;
}
}
else
{
# do something other
}
}
}