한 줄에서 여러 객체 선언에 대한 Jenkins 해석


9

이것은 질문이 아니라 오히려 조심스러운 이야기입니다. 나는 공간을 절약하려고 시도했으며 Jenkins Declarative pipeline에서 변수를 다음과 같이 선언했습니다.

int a, b, c

그런 다음 다음과 같이 초기화했습니다.

a = b = c = 0

내 코드에서는 이러한 정수를 for 루프의 카운터로 사용합니다. 내 스크립트는 계속해서 실패하고 몇 가지 예외가 발생했습니다.

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

내 목록이 하드 코딩되어 있기 때문에 유효한지 확인했습니다. 그래서이 카운터에서 무슨 일이 일어나고 있는지 궁금해하기 시작했고 getClass ()를 호출했을 때 Jenkins는 정수가 아니라고 말했습니다.

org.codehaus.groovy.runtime.NullObject

코드를

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

모든 것이 매력처럼 작동했습니다. 이것을 공유하고 싶었습니다. 어쩌면 누군가를 좌절시키는 데 도움이 될 것입니다.

답변:


12

Jenkins 파이프 라인은 groovy-cps 인터프리터를 사용하여 연속 전달 스타일로 Groovy 코드를 실행 합니다. IDE 또는 Groovy Shell에서 직접 실행할 수있는 바닐라 그루비가 아닙니다.

Groovy CPS는 다음과 같이 연속 전달 스타일과 올바른 Groovy 표현식을 지원하도록 코드를 변환합니다.

a = b = c = 0

다음과 같은 것으로 변형됩니다.

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

CPS 인터프리터에서이 표현식의 문제점은 할당이 값을 리턴하지 않으므로 null값이 변수에 지정되고 변수 b에 동일한 일이 발생한다는 것 a입니다.

CPS 호출 블록을 더 깊이 파고 싶다면 groovy-cps 프로젝트를 복제하고 com.cloudbees.groovy.cps.CpsTransformerTest클래스 에서 간단한 테스트 사례를 작성할 수 있습니다 .

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

그런 다음에 중단 점을두고 println cps디버거를 실행할 수 있습니다 . 검사 창을 열면 다음과 비슷한 그림이 나타납니다.

여기에 이미지 설명을 입력하십시오

참고로, Groovy 컴파일러는 코드를 바이트 코드로 컴파일 할 때 단일 행 할당도 변환한다는 점을 명심하십시오. 다음과 같은 간단한 Groovy 스크립트를 컴파일하는 경우 :

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

println "$a $b $c"

그런 다음 IDE에서 클래스 파일을 열어 바이트 코드를 Java와 동등한 것으로 디 컴파일하면 다음과 같이 표시됩니다.

//
// 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[]{"", " ", " ", ""}));
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.