Iterate FileWrapper, fails with shell script within the loop

2,639 views
Skip to first unread message

Sverre Moe

unread,
Oct 31, 2016, 7:22:08 AM10/31/16
to Jenkins Users
Problem looping through the result of findFiles.
The result from this method returns a org.jenkinsci.plugins.pipeline.utility.steps.fs.FileWrapper

node {
    stage
("Publish") {        
       
def files = findFiles(glob: '**/*.rpm')

       
for (def file : files) {
            sh
"echo Hello World! ${file.path}"
       
}
}
Fails with java.io.NotSerializableException: java.util.AbstractList$Itr

Trying to use @NonCPS
node {
    stage
("Publish") {
       
def files = findFiles(glob: '**/*.rpm')
        loopFiles
(files)
   
}
}

@NonCPS
void loopFiles(files) {
   
for (def file : files) {
        sh
"echo Hello World! ${file.path}"
   
}
}
It breaks the loop after first item in list. If 3 files found, then there is only one output.
However, if I remove the shell script and just use println it loops through all 3 files found.


Works if I loop the files first and put the file path in a new list:
node {
    stage
("Publish") {
       
def files = findFiles(glob: '**/*.rpm')
       
def packages = []
       
for (def file : files) {
            packages
.add(file.path)
       
}

       
for (def packagePath : packages) {
            sh
"echo Hello World! ${packagePath}"
       
}
}

I reckon that FileWrapper is not serializable, hence the problem, but why doesn't the @NonCPS work on all items?

Björn Pedersen

unread,
Nov 3, 2016, 11:56:41 AM11/3/16
to Jenkins Users

Björn Pedersen

unread,
Nov 3, 2016, 11:58:01 AM11/3/16
to Jenkins Users
And of course in methods marked  as NonCPS, you can not use jenkins steps (e.g. sh).

Björn

Sverre Moe

unread,
Nov 7, 2016, 7:04:40 AM11/7/16
to Jenkins Users
Was aware of it. Iterating for loops using for(def foo : foos) will work for List. Using closure forEach does not work in Pipeline without using @NonCPS.
  • Beware for (Foo f: foos) loops and Groovy closure-style operators like .each and the like. They will not work right in normal Pipeline script contexts where Pipeline steps are involved directly.
I have been using shell script within for (String f: foos) 
for (def file : files) {
  sh
"scp $file user@$server:$path"
}
This works fine. No problem at all. However this time I had problem iterating through a list of FileWrapper, regardless of existing shell script within or just a simple println of it. 

Thus, putting the iteration of FileWrapper within a method annotated with @NonCPS should fix that serializable problem.
However I was unaware the sh step could not be executed within a method annotated with @NonCPS. If that is mentioned in the documentation I must have missed it.

In any case, I have a workaround with first iterating the list of FileWrapper and putting it in a new list of Strings.
Reply all
Reply to author
Forward
0 new messages