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
gao wj
test-java2
Commits
45ea67e5
Commit
45ea67e5
authored
Oct 24, 2023
by
gao wj
Browse files
test-java2
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 @
45ea67e5
/*
* 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 @
45ea67e5
/*
* 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 @
45ea67e5
#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 @
45ea67e5
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 @
45ea67e5
File added
arthas-vmtool/target/classes/arthas/VmToolMXBean.class
0 → 100644
View file @
45ea67e5
File added
arthas-vmtool/target/classes/arthas/package-info.class
0 → 100644
View file @
45ea67e5
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$AAA.class
0 → 100644
View file @
45ea67e5
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$III.class
0 → 100644
View file @
45ea67e5
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest$LimitTest.class
0 → 100644
View file @
45ea67e5
File added
arthas-vmtool/target/test-classes/arthas/VmToolTest.class
0 → 100644
View file @
45ea67e5
File added
getCommittedMainFilesForCafehunterCli.sh
0 → 100644
View file @
45ea67e5
#!/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