Interpretasi Jenkins dari beberapa deklarasi objek pada satu baris

9

Ini bukan pertanyaan, melainkan kisah peringatan: Saya mencoba untuk menghemat ruang dan mendeklarasikan variabel saya dalam pipa Deklaratif Jenkins seperti:

int a, b, c

Kemudian, saya menginisialisasi mereka sebagai:

a = b = c = 0

Dalam kode saya, saya menggunakan bilangan bulat ini sebagai penghitung dalam for-loop. Skrip saya terus gagal berulang-ulang, beberapa pengecualian dilemparkan:

java.lang.NullPointerException: Cannot invoke method next() on null object

dan saya tahu pasti bahwa daftar saya valid karena sudah dikodekan dengan keras. Jadi, saya mulai bertanya-tanya apa yang terjadi dengan penghitung ini dan ketika saya memanggil getClass () pada mereka, Jenkins dengan senang mengatakan kepada saya bahwa mereka bukan bilangan bulat, melainkan

org.codehaus.groovy.runtime.NullObject

Setelah mengubah kode menjadi

int a = 0
int b = 0
int c = 0

semuanya bekerja seperti pesona. Hanya ingin membagikan ini. Mungkin itu akan membantu seseorang untuk menyelamatkan frustrasi.

Berkilau
sumber

Jawaban:

12

Pipa Jenkins mengeksekusi kode Groovy dalam gaya kelanjutan-lewat menggunakan juru bahasa -cov . Ini bukan vanilla Groovy yang bisa Anda jalankan langsung di IDE atau di Groovy Shell.

CPS Groovy mengubah kode Anda untuk mendukung gaya passing-kelanjutan dan ekspresi Groovy yang benar seperti:

a = b = c = 0

ditransformasikan menjadi sesuatu yang lebih mirip:

eval(
  var("a"), 
  assign(
    eval(
      var("b"), 
      assign(
        eval(
          var("c"), 
          assign(0)
        )
      )
    )
  )
)

Masalah dengan ungkapan ini dalam interpreter CPS adalah bahwa penugasan tidak mengembalikan nilai apa pun, dan dengan demikian nullnilai akan ditugaskan ke variabel b, dan hal yang sama terjadi pada variabel a.

Jika Anda ingin menggali lebih dalam di blok doa CPS, Anda dapat mengkloning proyek groovy-cps dan menulis test case sederhana di com.cloudbees.groovy.cps.CpsTransformerTestkelas.

@Test
void testMultiVariablesInlineCPS() {
    def cps = parseCps('''
int a, b, c
a = b = c = 0
''')
    println cps
}

Kemudian Anda bisa meletakkan breakpoint di println cpsdan menjalankan debugger. Saat Anda membuka jendela inspeksi, Anda akan melihat gambar yang mirip dengan ini:

masukkan deskripsi gambar di sini

Sebagai catatan, perlu diingat bahwa kompiler Groovy juga mengubah tugas baris tunggal Anda ketika mengkompilasi kode menjadi bytecode. Jika Anda menyusun skrip Groovy sederhana seperti:

int a, b, c
a = b = c = 0

println "$a $b $c"

dan kemudian Anda membuka file kelasnya di IDE untuk mendekompilasi bytecode ke Java, Anda akan melihat sesuatu seperti ini:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

import groovy.lang.Binding;
import groovy.lang.Script;
import org.codehaus.groovy.runtime.GStringImpl;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.callsite.CallSite;

public class test extends Script {
    public test() {
        CallSite[] var1 = $getCallSiteArray();
    }

    public test(Binding context) {
        CallSite[] var2 = $getCallSiteArray();
        super(context);
    }

    public static void main(String... args) {
        CallSite[] var1 = $getCallSiteArray();
        var1[0].call(InvokerHelper.class, test.class, args);
    }

    public Object run() {
        CallSite[] var1 = $getCallSiteArray();
        int a = 0;
        int b = 0;
        int c = 0;
        byte var5 = 0;
        return var1[1].callCurrent(this, new GStringImpl(new Object[]{Integer.valueOf(var5), Integer.valueOf(var5), Integer.valueOf(var5)}, new String[]{"", " ", " ", ""}));
    }
}
Szymon Stepniak
sumber