Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Administrator
Public Java Test
Commits
c3b2ba6c
Commit
c3b2ba6c
authored
Oct 23, 2023
by
shengnan hu
Browse files
init
parents
Changes
32
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
515 additions
and
0 deletions
+515
-0
arthas-vmtool/src/main/native/head/windows/jawt_md.h
arthas-vmtool/src/main/native/head/windows/jawt_md.h
+59
-0
arthas-vmtool/src/main/native/head/windows/jni_md.h
arthas-vmtool/src/main/native/head/windows/jni_md.h
+40
-0
arthas-vmtool/src/main/native/src/jni-library.cpp
arthas-vmtool/src/main/native/src/jni-library.cpp
+208
-0
arthas-vmtool/src/test/java/arthas/VmToolTest.java
arthas-vmtool/src/test/java/arthas/VmToolTest.java
+185
-0
arthas-vmtool/target/classes/arthas/VmTool.class
arthas-vmtool/target/classes/arthas/VmTool.class
+0
-0
arthas-vmtool/target/classes/arthas/VmToolMXBean.class
arthas-vmtool/target/classes/arthas/VmToolMXBean.class
+0
-0
arthas-vmtool/target/classes/arthas/package-info.class
arthas-vmtool/target/classes/arthas/package-info.class
+0
-0
arthas-vmtool/target/test-classes/arthas/VmToolTest$AAA.class
...as-vmtool/target/test-classes/arthas/VmToolTest$AAA.class
+0
-0
arthas-vmtool/target/test-classes/arthas/VmToolTest$III.class
...as-vmtool/target/test-classes/arthas/VmToolTest$III.class
+0
-0
arthas-vmtool/target/test-classes/arthas/VmToolTest$LimitTest.class
...ool/target/test-classes/arthas/VmToolTest$LimitTest.class
+0
-0
arthas-vmtool/target/test-classes/arthas/VmToolTest.class
arthas-vmtool/target/test-classes/arthas/VmToolTest.class
+0
-0
getCommittedMainFilesForCafehunterCli.sh
getCommittedMainFilesForCafehunterCli.sh
+23
-0
No files found.
arthas-vmtool/src/main/native/head/windows/jawt_md.h
0 → 100644
View file @
c3b2ba6c
/*
* Copyright (c) 1999, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JAWT_MD_H_
#define _JAVASOFT_JAWT_MD_H_
#include <windows.h>
#include "jawt.h"
#ifdef __cplusplus
extern
"C"
{
#endif
/*
* Win32-specific declarations for AWT native interface.
* See notes in jawt.h for an example of use.
*/
typedef
struct
jawt_Win32DrawingSurfaceInfo
{
/* Native window, DDB, or DIB handle */
union
{
HWND
hwnd
;
HBITMAP
hbitmap
;
void
*
pbits
;
};
/*
* This HDC should always be used instead of the HDC returned from
* BeginPaint() or any calls to GetDC().
*/
HDC
hdc
;
HPALETTE
hpalette
;
}
JAWT_Win32DrawingSurfaceInfo
;
#ifdef __cplusplus
}
#endif
#endif
/* !_JAVASOFT_JAWT_MD_H_ */
arthas-vmtool/src/main/native/head/windows/jni_md.h
0 → 100644
View file @
c3b2ba6c
/*
* Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#ifndef _JAVASOFT_JNI_MD_H_
#define _JAVASOFT_JNI_MD_H_
#ifndef JNIEXPORT
#define JNIEXPORT __declspec(dllexport)
#endif
#define JNIIMPORT __declspec(dllimport)
#define JNICALL __stdcall
// 'long' is always 32 bit on windows so this matches what jdk expects
typedef
long
jint
;
typedef
__int64
jlong
;
typedef
signed
char
jbyte
;
#endif
/* !_JAVASOFT_JNI_MD_H_ */
arthas-vmtool/src/main/native/src/jni-library.cpp
0 → 100644
View file @
c3b2ba6c
#include <iostream>
#include <jni.h>
#include <jni_md.h>
#include <jvmti.h>
#include "arthas_VmTool.h" // under target/native/javah/
static
jvmtiEnv
*
jvmti
;
static
jlong
tagCounter
=
0
;
struct
LimitCounter
{
jint
currentCounter
;
jint
limitValue
;
void
init
(
jint
limit
)
{
currentCounter
=
0
;
limitValue
=
limit
;
}
void
countDown
()
{
currentCounter
++
;
}
bool
allow
()
{
if
(
limitValue
<
0
)
{
return
true
;
}
return
limitValue
>
currentCounter
;
}
};
// 每次 IterateOverInstancesOfClass 调用前需要先 init
static
LimitCounter
limitCounter
=
{
0
,
0
};
extern
"C"
int
init_agent
(
JavaVM
*
vm
,
void
*
reserved
)
{
jint
rc
;
/* Get JVMTI environment */
rc
=
vm
->
GetEnv
((
void
**
)
&
jvmti
,
JVMTI_VERSION_1_2
);
if
(
rc
!=
JNI_OK
)
{
fprintf
(
stderr
,
"ERROR: arthas vmtool Unable to create jvmtiEnv, GetEnv failed, error=%d
\n
"
,
rc
);
return
-
1
;
}
jvmtiCapabilities
capabilities
=
{
0
};
capabilities
.
can_tag_objects
=
1
;
jvmtiError
error
=
jvmti
->
AddCapabilities
(
&
capabilities
);
if
(
error
)
{
fprintf
(
stderr
,
"ERROR: arthas vmtool JVMTI AddCapabilities failed!%u
\n
"
,
error
);
return
JNI_FALSE
;
}
return
JNI_OK
;
}
extern
"C"
JNIEXPORT
jint
JNICALL
Agent_OnLoad
(
JavaVM
*
vm
,
char
*
options
,
void
*
reserved
)
{
return
init_agent
(
vm
,
reserved
);
}
extern
"C"
JNIEXPORT
jint
JNICALL
Agent_OnAttach
(
JavaVM
*
vm
,
char
*
options
,
void
*
reserved
)
{
return
init_agent
(
vm
,
reserved
);
}
extern
"C"
JNIEXPORT
jint
JNICALL
JNI_OnLoad
(
JavaVM
*
vm
,
void
*
reserved
)
{
init_agent
(
vm
,
reserved
);
return
JNI_VERSION_1_6
;
}
extern
"C"
JNIEXPORT
void
JNICALL
Java_arthas_VmTool_forceGc0
(
JNIEnv
*
env
,
jclass
thisClass
)
{
jvmti
->
ForceGarbageCollection
();
}
extern
"C"
jlong
getTag
()
{
return
++
tagCounter
;
}
extern
"C"
jvmtiIterationControl
JNICALL
HeapObjectCallback
(
jlong
class_tag
,
jlong
size
,
jlong
*
tag_ptr
,
void
*
user_data
)
{
jlong
*
data
=
static_cast
<
jlong
*>
(
user_data
);
*
tag_ptr
=
*
data
;
limitCounter
.
countDown
();
if
(
limitCounter
.
allow
())
{
return
JVMTI_ITERATION_CONTINUE
;
}
else
{
return
JVMTI_ITERATION_ABORT
;
}
}
extern
"C"
JNIEXPORT
jobjectArray
JNICALL
Java_arthas_VmTool_getInstances0
(
JNIEnv
*
env
,
jclass
thisClass
,
jclass
klass
,
jint
limit
)
{
jlong
tag
=
getTag
();
limitCounter
.
init
(
limit
);
jvmtiError
error
=
jvmti
->
IterateOverInstancesOfClass
(
klass
,
JVMTI_HEAP_OBJECT_EITHER
,
HeapObjectCallback
,
&
tag
);
if
(
error
)
{
printf
(
"ERROR: JVMTI IterateOverInstancesOfClass failed!%u
\n
"
,
error
);
return
NULL
;
}
jint
count
=
0
;
jobject
*
instances
;
error
=
jvmti
->
GetObjectsWithTags
(
1
,
&
tag
,
&
count
,
&
instances
,
NULL
);
if
(
error
)
{
printf
(
"ERROR: JVMTI GetObjectsWithTags failed!%u
\n
"
,
error
);
return
NULL
;
}
jobjectArray
array
=
env
->
NewObjectArray
(
count
,
klass
,
NULL
);
//添加元素到数组
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
env
->
SetObjectArrayElement
(
array
,
i
,
instances
[
i
]);
}
jvmti
->
Deallocate
(
reinterpret_cast
<
unsigned
char
*>
(
instances
));
return
array
;
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_arthas_VmTool_sumInstanceSize0
(
JNIEnv
*
env
,
jclass
thisClass
,
jclass
klass
)
{
jlong
tag
=
getTag
();
limitCounter
.
init
(
-
1
);
jvmtiError
error
=
jvmti
->
IterateOverInstancesOfClass
(
klass
,
JVMTI_HEAP_OBJECT_EITHER
,
HeapObjectCallback
,
&
tag
);
if
(
error
)
{
printf
(
"ERROR: JVMTI IterateOverInstancesOfClass failed!%u
\n
"
,
error
);
return
-
1
;
}
jint
count
=
0
;
jobject
*
instances
;
error
=
jvmti
->
GetObjectsWithTags
(
1
,
&
tag
,
&
count
,
&
instances
,
NULL
);
if
(
error
)
{
printf
(
"ERROR: JVMTI GetObjectsWithTags failed!%u
\n
"
,
error
);
return
-
1
;
}
jlong
sum
=
0
;
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
jlong
size
=
0
;
jvmti
->
GetObjectSize
(
instances
[
i
],
&
size
);
sum
=
sum
+
size
;
}
jvmti
->
Deallocate
(
reinterpret_cast
<
unsigned
char
*>
(
instances
));
return
sum
;
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_arthas_VmTool_getInstanceSize0
(
JNIEnv
*
env
,
jclass
thisClass
,
jobject
instance
)
{
jlong
size
=
-
1
;
jvmtiError
error
=
jvmti
->
GetObjectSize
(
instance
,
&
size
);
if
(
error
)
{
printf
(
"ERROR: JVMTI GetObjectSize failed!%u
\n
"
,
error
);
}
return
size
;
}
extern
"C"
JNIEXPORT
jlong
JNICALL
Java_arthas_VmTool_countInstances0
(
JNIEnv
*
env
,
jclass
thisClass
,
jclass
klass
)
{
jlong
tag
=
getTag
();
limitCounter
.
init
(
-
1
);
jvmtiError
error
=
jvmti
->
IterateOverInstancesOfClass
(
klass
,
JVMTI_HEAP_OBJECT_EITHER
,
HeapObjectCallback
,
&
tag
);
if
(
error
)
{
printf
(
"ERROR: JVMTI IterateOverInstancesOfClass failed!%u
\n
"
,
error
);
return
-
1
;
}
jint
count
=
0
;
error
=
jvmti
->
GetObjectsWithTags
(
1
,
&
tag
,
&
count
,
NULL
,
NULL
);
if
(
error
)
{
printf
(
"ERROR: JVMTI GetObjectsWithTags failed!%u
\n
"
,
error
);
return
-
1
;
}
return
count
;
}
extern
"C"
JNIEXPORT
jobjectArray
JNICALL
Java_arthas_VmTool_getAllLoadedClasses0
(
JNIEnv
*
env
,
jclass
thisClass
,
jclass
kclass
)
{
jclass
*
classes
;
jint
count
=
0
;
jvmtiError
error
=
jvmti
->
GetLoadedClasses
(
&
count
,
&
classes
);
if
(
error
)
{
printf
(
"ERROR: JVMTI GetLoadedClasses failed!
\n
"
);
return
NULL
;
}
jobjectArray
array
=
env
->
NewObjectArray
(
count
,
kclass
,
NULL
);
//添加元素到数组
for
(
int
i
=
0
;
i
<
count
;
i
++
)
{
env
->
SetObjectArrayElement
(
array
,
i
,
classes
[
i
]);
}
jvmti
->
Deallocate
(
reinterpret_cast
<
unsigned
char
*>
(
classes
));
return
array
;
}
\ No newline at end of file
arthas-vmtool/src/test/java/arthas/VmToolTest.java
0 → 100644
View file @
c3b2ba6c
package
arthas
;
import
java.io.File
;
import
java.lang.ref.WeakReference
;
import
java.util.ArrayList
;
import
java.util.concurrent.atomic.AtomicLong
;
import
org.assertj.core.api.Assertions
;
import
org.junit.Test
;
import
com.taobao.arthas.common.VmToolUtils
;
/**
* 以下本地测试的jvm参数均为:-Xms128m -Xmx128m
*/
public
class
VmToolTest
{
private
VmTool
initVmTool
()
{
File
path
=
new
File
(
VmTool
.
class
.
getProtectionDomain
().
getCodeSource
().
getLocation
().
getPath
()).
getParentFile
();
String
libPath
=
new
File
(
path
,
VmToolUtils
.
detectLibName
()).
getAbsolutePath
();
return
VmTool
.
getInstance
(
libPath
);
}
/**
* macbook上运行结果如下
* allLoadedClasses->1050
* arthas.VmTool@5bb21b69 arthas.VmTool@6b9651f3
* before instances->[arthas.VmTool@5bb21b69, arthas.VmTool@6b9651f3]
* size->16
* count->2
* sum size->32
* null null
* after instances->[]
*/
@Test
public
void
testIsSnapshot
()
{
try
{
VmTool
vmtool
=
initVmTool
();
//调用native方法,获取已加载的类,不包括小类型(如int)
Class
<?>[]
allLoadedClasses
=
vmtool
.
getAllLoadedClasses
();
System
.
out
.
println
(
"allLoadedClasses->"
+
allLoadedClasses
.
length
);
//通过下面的例子,可以看到getInstances(Class<T> klass)拿到的是当前存活的所有对象
WeakReference
<
VmToolTest
>
weakReference1
=
new
WeakReference
<
VmToolTest
>(
new
VmToolTest
());
WeakReference
<
VmToolTest
>
weakReference2
=
new
WeakReference
<
VmToolTest
>(
new
VmToolTest
());
System
.
out
.
println
(
weakReference1
.
get
()
+
" "
+
weakReference2
.
get
());
VmTool
[]
beforeInstances
=
vmtool
.
getInstances
(
VmTool
.
class
);
System
.
out
.
println
(
"before instances->"
+
beforeInstances
);
System
.
out
.
println
(
"size->"
+
vmtool
.
getInstanceSize
(
weakReference1
.
get
()));
System
.
out
.
println
(
"count->"
+
vmtool
.
countInstances
(
VmTool
.
class
));
System
.
out
.
println
(
"sum size->"
+
vmtool
.
sumInstanceSize
(
VmTool
.
class
));
beforeInstances
=
null
;
vmtool
.
forceGc
();
Thread
.
sleep
(
100
);
System
.
out
.
println
(
weakReference1
.
get
()
+
" "
+
weakReference2
.
get
());
VmTool
[]
afterInstances
=
vmtool
.
getInstances
(
VmTool
.
class
);
System
.
out
.
println
(
"after instances->"
+
afterInstances
);
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
}
@Test
public
void
testGetInstancesMemoryLeak
()
{
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool
vmtool
=
initVmTool
();
final
AtomicLong
totalTime
=
new
AtomicLong
();
//本地测试请改成200000
for
(
int
i
=
1
;
i
<=
2
;
i
++)
{
long
start
=
System
.
currentTimeMillis
();
WeakReference
<
Object
[]>
reference
=
new
WeakReference
<
Object
[]>(
vmtool
.
getInstances
(
Object
.
class
));
Object
[]
instances
=
reference
.
get
();
long
cost
=
System
.
currentTimeMillis
()
-
start
;
totalTime
.
addAndGet
(
cost
);
System
.
out
.
println
(
i
+
" instance size:"
+
(
instances
==
null
?
0
:
instances
.
length
)
+
", cost "
+
cost
+
"ms avgCost "
+
totalTime
.
doubleValue
()
/
i
+
"ms"
);
instances
=
null
;
vmtool
.
forceGc
();
}
}
@Test
public
void
testSumInstancesMemoryLeak
()
{
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool
vmtool
=
initVmTool
();
final
AtomicLong
totalTime
=
new
AtomicLong
();
//本地测试请改成200000
for
(
int
i
=
1
;
i
<=
2
;
i
++)
{
long
start
=
System
.
currentTimeMillis
();
long
sum
=
vmtool
.
sumInstanceSize
(
Object
.
class
);
long
cost
=
System
.
currentTimeMillis
()
-
start
;
totalTime
.
addAndGet
(
cost
);
System
.
out
.
println
(
i
+
" sum:"
+
sum
+
", cost "
+
cost
+
"ms avgCost "
+
totalTime
.
doubleValue
()
/
i
+
"ms"
);
}
}
@Test
public
void
testCountInstancesMemoryLeak
()
{
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool
vmtool
=
initVmTool
();
final
AtomicLong
totalTime
=
new
AtomicLong
();
//本地测试请改成200000
for
(
int
i
=
1
;
i
<=
2
;
i
++)
{
long
start
=
System
.
currentTimeMillis
();
long
count
=
vmtool
.
countInstances
(
Object
.
class
);
long
cost
=
System
.
currentTimeMillis
()
-
start
;
totalTime
.
addAndGet
(
cost
);
System
.
out
.
println
(
i
+
" count:"
+
count
+
", cost "
+
cost
+
"ms avgCost "
+
totalTime
.
doubleValue
()
/
i
+
"ms"
);
}
}
@Test
public
void
testGetAllLoadedClassesMemoryLeak
()
{
//这里睡20s是为了方便用jprofiler连接上进程
// try {
// Thread.sleep(20000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
VmTool
vmtool
=
initVmTool
();
final
AtomicLong
totalTime
=
new
AtomicLong
();
//本地测试请改成200000
for
(
int
i
=
1
;
i
<=
2
;
i
++)
{
long
start
=
System
.
currentTimeMillis
();
Class
<?>[]
allLoadedClasses
=
vmtool
.
getAllLoadedClasses
();
long
cost
=
System
.
currentTimeMillis
()
-
start
;
totalTime
.
addAndGet
(
cost
);
System
.
out
.
println
(
i
+
" class size:"
+
allLoadedClasses
.
length
+
", cost "
+
cost
+
"ms avgCost "
+
totalTime
.
doubleValue
()
/
i
+
"ms"
);
allLoadedClasses
=
null
;
}
}
class
LimitTest
{
}
@Test
public
void
test_getInstances_lmiit
()
{
VmTool
vmtool
=
initVmTool
();
ArrayList
<
LimitTest
>
list
=
new
ArrayList
<
LimitTest
>();
for
(
int
i
=
0
;
i
<
10
;
++
i
)
{
list
.
add
(
new
LimitTest
());
}
LimitTest
[]
instances
=
vmtool
.
getInstances
(
LimitTest
.
class
,
5
);
Assertions
.
assertThat
(
instances
).
hasSize
(
5
);
LimitTest
[]
instances2
=
vmtool
.
getInstances
(
LimitTest
.
class
,
-
1
);
Assertions
.
assertThat
(
instances2
).
hasSize
(
10
);
LimitTest
[]
instances3
=
vmtool
.
getInstances
(
LimitTest
.
class
,
1
);
Assertions
.
assertThat
(
instances3
).
hasSize
(
1
);
}
interface
III
{
}
class
AAA
implements
III
{
}
@Test
public
void
test_getInstances_interface
()
{
AAA
aaa
=
new
AAA
();
VmTool
vmtool
=
initVmTool
();
III
[]
interfaceInstances
=
vmtool
.
getInstances
(
III
.
class
);
Assertions
.
assertThat
(
interfaceInstances
.
length
).
isEqualTo
(
1
);
AAA
[]
ObjectInstances
=
vmtool
.
getInstances
(
AAA
.
class
);
Assertions
.
assertThat
(
ObjectInstances
.
length
).
isEqualTo
(
1
);
Assertions
.
assertThat
(
interfaceInstances
[
0
]).
isEqualTo
(
ObjectInstances
[
0
]);
}
}
arthas-vmtool/target/classes/arthas/VmTool.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/classes/arthas/VmToolMXBean.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/classes/arthas/package-info.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$AAA.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$III.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$LimitTest.class
0 → 100644
View file @
c3b2ba6c
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest.class
0 → 100644
View file @
c3b2ba6c
File added
getCommittedMainFilesForCafehunterCli.sh
0 → 100644
View file @
c3b2ba6c
#!/bin/bash
function
build
()
{
local
-a
COMMITTED_FILES
COMMITTED_FILES
=
$(
git diff
--name-only
--diff-filter
=
DCM
$CI_COMMIT_SHA
origin/
$CI_MERGE_REQUEST_TARGET_BRANCH_NAME
)
if
[
-z
"
$COMMITTED_FILES
"
]
;
then
return
fi
local
-a
check_files
for
dir
in
$COMMITTED_FILES
;
do
if
[[
$dir
=
~
${
JAVA_MAIN_SOURCE
}
]]
;
then
#如果不是 则跳过剩下的步骤
check_files+
=(
"
$REPOSITORY_FULL_PATH
/"
${
dir
}
)
fi
done
if
[
-z
"
$check_files
"
]
;
then
return
fi
S
=
$(
IFS
=
' '
;
echo
"
${
check_files
[*]
}
"
)
echo
$S
}
build
"
$@
"
Prev
1
2
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment