Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
roginluo
Jenkins
提交
c68cfc9d
J
Jenkins
项目概览
roginluo
/
Jenkins
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
Jenkins
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c68cfc9d
编写于
3月 04, 2014
作者:
J
Jesse Glick
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Introduced LazyBuildMixIn.
上级
2ea3d8f1
变更
5
隐藏空白更改
内联
并排
Showing
5 changed file
with
342 addition
and
118 deletion
+342
-118
core/src/main/java/hudson/matrix/MatrixConfiguration.java
core/src/main/java/hudson/matrix/MatrixConfiguration.java
+1
-1
core/src/main/java/hudson/model/AbstractBuild.java
core/src/main/java/hudson/model/AbstractBuild.java
+1
-1
core/src/main/java/hudson/model/AbstractProject.java
core/src/main/java/hudson/model/AbstractProject.java
+30
-115
core/src/main/java/hudson/model/Job.java
core/src/main/java/hudson/model/Job.java
+13
-1
core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java
core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java
+297
-0
未找到文件。
core/src/main/java/hudson/matrix/MatrixConfiguration.java
浏览文件 @
c68cfc9d
...
...
@@ -248,7 +248,7 @@ public class MatrixConfiguration extends Project<MatrixConfiguration,MatrixRun>
lastBuild
.
number
=
lb
.
getNumber
();
builds
.
put
(
lastBuild
);
_getRuns
()
.
put
(
lastBuild
);
return
lastBuild
;
}
...
...
core/src/main/java/hudson/model/AbstractBuild.java
浏览文件 @
c68cfc9d
...
...
@@ -244,7 +244,7 @@ public abstract class AbstractBuild<P extends AbstractProject<P,R>,R extends Abs
if
(
r
==
null
)
{
// having two neighbors pointing to each other is important to make RunMap.removeValue work
R
nb
=
getParent
().
builds
.
search
(
number
+
1
,
Direction
.
ASC
);
R
nb
=
getParent
().
_getRuns
()
.
search
(
number
+
1
,
Direction
.
ASC
);
if
(
nb
!=
null
)
{
((
AbstractBuild
)
nb
).
previousBuild
=
selfReference
;
// establish bi-di link
this
.
nextBuild
=
nb
.
selfReference
;
...
...
core/src/main/java/hudson/model/AbstractProject.java
浏览文件 @
c68cfc9d
...
...
@@ -32,7 +32,6 @@ import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
import
hudson.AbortException
;
import
hudson.CopyOnWrite
;
import
hudson.EnvVars
;
import
hudson.Extension
;
import
hudson.ExtensionPoint
;
import
hudson.FeedAdapter
;
import
hudson.FilePath
;
...
...
@@ -49,7 +48,6 @@ import hudson.model.Fingerprint.RangeSet;
import
hudson.model.PermalinkProjectAction.Permalink
;
import
hudson.model.Queue.Executable
;
import
hudson.model.Queue.Task
;
import
hudson.model.RunMap.Constructor
;
import
hudson.model.labels.LabelAtom
;
import
hudson.model.labels.LabelExpression
;
import
hudson.model.listeners.ItemListener
;
...
...
@@ -86,11 +84,9 @@ import hudson.util.AlternativeUiTextProvider.Message;
import
hudson.util.DescribableList
;
import
hudson.util.FormValidation
;
import
hudson.util.TimeUnit2
;
import
hudson.widgets.BuildHistoryWidget
;
import
hudson.widgets.HistoryWidget
;
import
java.io.File
;
import
java.io.IOException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Calendar
;
...
...
@@ -118,7 +114,7 @@ import jenkins.model.Jenkins;
import
jenkins.model.JenkinsLocationConfiguration
;
import
jenkins.model.ModelObjectWithChildren
;
import
jenkins.model.Uptime
;
import
jenkins.model.lazy.
AbstractLazyLoadRunMap.Directio
n
;
import
jenkins.model.lazy.
LazyBuildMixI
n
;
import
jenkins.scm.DefaultSCMCheckoutStrategyImpl
;
import
jenkins.scm.SCMCheckoutStrategy
;
import
jenkins.scm.SCMCheckoutStrategyDescriptor
;
...
...
@@ -129,7 +125,6 @@ import org.acegisecurity.context.SecurityContext;
import
org.acegisecurity.context.SecurityContextHolder
;
import
org.jenkinsci.bytecode.AdaptField
;
import
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.DoNotUse
;
import
org.kohsuke.accmod.restrictions.NoExternalUse
;
import
org.kohsuke.args4j.Argument
;
import
org.kohsuke.args4j.CmdLineException
;
...
...
@@ -173,15 +168,16 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
private
volatile
transient
SCMRevisionState
pollingBaseline
=
null
;
private
transient
LazyBuildMixIn
<
P
,
R
>
buildMixIn
;
/**
* All the builds keyed by their build number.
*
*
Kept here for binary compatibility only; otherwise use {@link #buildMixIn}.
* External code should use {@link #getBuildByNumber(int)} or {@link #getLastBuild()} and traverse via
* {@link Run#getPreviousBuild()}
*/
@Restricted
(
NoExternalUse
.
class
)
@SuppressWarnings
(
"deprecation"
)
// [JENKINS-15156] builds accessed before onLoad or onCreatedFromScratch called
protected
transient
RunMap
<
R
>
builds
=
new
RunMap
<
R
>();
protected
transient
RunMap
<
R
>
builds
;
/**
* The quiet period. Null to delegate to the system default.
...
...
@@ -274,6 +270,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
protected
AbstractProject
(
ItemGroup
parent
,
String
name
)
{
super
(
parent
,
name
);
initBuildMixIn
();
if
(
Jenkins
.
getInstance
()!=
null
&&
!
Jenkins
.
getInstance
().
getNodes
().
isEmpty
())
{
// if a new job is configured with Hudson that already has slave nodes
...
...
@@ -282,6 +279,15 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
}
}
private
void
initBuildMixIn
()
{
buildMixIn
=
new
LazyBuildMixIn
<
P
,
R
>(
this
)
{
@Override
protected
Class
<
R
>
getBuildClass
()
{
return
AbstractProject
.
this
.
getBuildClass
();
}
};
builds
=
buildMixIn
.
getRunMap
();
}
@Override
public
synchronized
void
save
()
throws
IOException
{
super
.
save
();
...
...
@@ -291,7 +297,8 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
@Override
public
void
onCreatedFromScratch
()
{
super
.
onCreatedFromScratch
();
builds
=
createBuildRunMap
();
buildMixIn
.
onCreatedFromScratch
();
builds
=
buildMixIn
.
getRunMap
();
// solicit initial contributions, especially from TransientProjectActionFactory
updateTransientActions
();
}
...
...
@@ -299,33 +306,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
@Override
public
void
onLoad
(
ItemGroup
<?
extends
Item
>
parent
,
String
name
)
throws
IOException
{
super
.
onLoad
(
parent
,
name
);
RunMap
<
R
>
builds
=
createBuildRunMap
();
RunMap
<
R
>
currentBuilds
=
this
.
builds
;
if
(
currentBuilds
==
null
&&
parent
!=
null
)
{
// are we overwriting what currently exist?
// this is primarily when Jenkins is getting reloaded
Item
current
;
try
{
current
=
parent
.
getItem
(
name
);
}
catch
(
RuntimeException
x
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"failed to look up "
+
name
+
" in "
+
parent
,
x
);
current
=
null
;
}
if
(
current
!=
null
&&
current
.
getClass
()==
getClass
())
{
currentBuilds
=
((
AbstractProject
)
current
).
builds
;
}
}
if
(
currentBuilds
!=
null
)
{
// if we are reloading, keep all those that are still building intact
for
(
R
r
:
currentBuilds
.
getLoadedBuilds
().
values
())
{
if
(
r
.
isBuilding
())
builds
.
put
(
r
);
}
}
this
.
builds
=
builds
;
initBuildMixIn
();
triggers
().
setOwner
(
this
);
for
(
Trigger
t
:
triggers
())
{
t
.
start
(
this
,
Items
.
currentlyUpdatingByXml
());
...
...
@@ -338,14 +319,6 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
updateTransientActions
();
}
private
RunMap
<
R
>
createBuildRunMap
()
{
return
new
RunMap
<
R
>(
getBuildDir
(),
new
Constructor
<
R
>()
{
public
R
create
(
File
dir
)
throws
IOException
{
return
loadBuild
(
dir
);
}
});
}
@WithBridgeMethods
(
List
.
class
)
protected
DescribableList
<
Trigger
<?>,
TriggerDescriptor
>
triggers
()
{
if
(
triggers
==
null
)
{
...
...
@@ -1039,18 +1012,12 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
@Override
public
RunMap
<
R
>
_getRuns
()
{
if
(
builds
==
null
)
{
throw
new
IllegalStateException
(
"no run map created yet for "
+
this
);
}
assert
builds
.
baseDirInitialized
()
:
"neither onCreatedFromScratch nor onLoad called on "
+
this
+
" yet"
;
return
builds
;
return
buildMixIn
.
_getRuns
();
}
@Override
public
void
removeRun
(
R
run
)
{
if
(!
this
.
builds
.
remove
(
run
))
{
LOGGER
.
log
(
Level
.
WARNING
,
"{0} did not contain {1} to begin with"
,
new
Object
[]
{
this
,
run
});
}
buildMixIn
.
removeRun
(
run
);
}
/**
...
...
@@ -1060,7 +1027,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
@Override
public
R
getBuild
(
String
id
)
{
return
build
s
.
getByI
d
(
id
);
return
build
MixIn
.
getBuil
d
(
id
);
}
/**
...
...
@@ -1070,7 +1037,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
@Override
public
R
getBuildByNumber
(
int
n
)
{
return
build
s
.
get
ByNumber
(
n
);
return
build
MixIn
.
getBuild
ByNumber
(
n
);
}
/**
...
...
@@ -1080,22 +1047,22 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
@Override
public
R
getFirstBuild
()
{
return
build
s
.
olde
stBuild
();
return
build
MixIn
.
getFir
stBuild
();
}
@Override
public
@CheckForNull
R
getLastBuild
()
{
return
build
s
.
newe
stBuild
();
return
build
MixIn
.
getLa
stBuild
();
}
@Override
public
R
getNearestBuild
(
int
n
)
{
return
build
s
.
search
(
n
,
Direction
.
ASC
);
return
build
MixIn
.
getNearestBuild
(
n
);
}
@Override
public
R
getNearestOldBuild
(
int
n
)
{
return
build
s
.
search
(
n
,
Direction
.
DESC
);
return
build
MixIn
.
getNearestOldBuild
(
n
);
}
/**
...
...
@@ -1106,61 +1073,19 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
*/
protected
abstract
Class
<
R
>
getBuildClass
();
// keep track of the previous time we started a build
private
transient
long
lastBuildStartTime
;
/**
* Creates a new build of this project for immediate execution.
* Suitable for {@link SubTask#createExecutable}.
*/
protected
synchronized
R
newBuild
()
throws
IOException
{
// make sure we don't start two builds in the same second
// so the build directories will be different too
long
timeSinceLast
=
System
.
currentTimeMillis
()
-
lastBuildStartTime
;
if
(
timeSinceLast
<
1000
)
{
try
{
Thread
.
sleep
(
1000
-
timeSinceLast
);
}
catch
(
InterruptedException
e
)
{
}
}
lastBuildStartTime
=
System
.
currentTimeMillis
();
try
{
R
lastBuild
=
getBuildClass
().
getConstructor
(
getClass
()).
newInstance
(
this
);
builds
.
put
(
lastBuild
);
return
lastBuild
;
}
catch
(
InstantiationException
e
)
{
throw
new
Error
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
Error
(
e
);
}
catch
(
InvocationTargetException
e
)
{
throw
handleInvocationTargetException
(
e
);
}
catch
(
NoSuchMethodException
e
)
{
throw
new
Error
(
e
);
}
}
private
IOException
handleInvocationTargetException
(
InvocationTargetException
e
)
{
Throwable
t
=
e
.
getTargetException
();
if
(
t
instanceof
Error
)
throw
(
Error
)
t
;
if
(
t
instanceof
RuntimeException
)
throw
(
RuntimeException
)
t
;
if
(
t
instanceof
IOException
)
return
(
IOException
)
t
;
throw
new
Error
(
t
);
return
buildMixIn
.
newBuild
();
}
/**
* Loads an existing build record from disk.
*/
protected
R
loadBuild
(
File
dir
)
throws
IOException
{
try
{
return
getBuildClass
().
getConstructor
(
getClass
(),
File
.
class
).
newInstance
(
this
,
dir
);
}
catch
(
InstantiationException
e
)
{
throw
new
Error
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
Error
(
e
);
}
catch
(
InvocationTargetException
e
)
{
throw
handleInvocationTargetException
(
e
);
}
catch
(
NoSuchMethodException
e
)
{
throw
new
Error
(
e
);
}
return
buildMixIn
.
loadBuild
(
dir
);
}
/**
...
...
@@ -1820,7 +1745,7 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
@Override
protected
HistoryWidget
createHistoryWidget
()
{
return
new
BuildHistoryWidget
<
R
>(
this
,
builds
,
HISTORY_ADAPTER
);
return
buildMixIn
.
createHistoryWidget
(
);
}
public
boolean
isParameterized
()
{
...
...
@@ -2426,14 +2351,4 @@ public abstract class AbstractProject<P extends AbstractProject<P,R>,R extends A
public
abstract
FormValidation
check
(
@Nonnull
AbstractProject
<?,
?>
project
,
@Nonnull
Label
label
);
}
@Restricted
(
DoNotUse
.
class
)
@Extension
public
static
final
class
ItemListenerImpl
extends
ItemListener
{
@Override
public
void
onLocationChanged
(
Item
item
,
String
oldFullName
,
String
newFullName
)
{
if
(
item
instanceof
AbstractProject
)
{
AbstractProject
p
=
(
AbstractProject
)
item
;
p
.
builds
.
updateBaseDir
(
p
.
getBuildDir
());
}
}
}
}
core/src/main/java/hudson/model/Job.java
浏览文件 @
c68cfc9d
...
...
@@ -98,6 +98,7 @@ import java.util.*;
import
java.util.List
;
import
static
javax
.
servlet
.
http
.
HttpServletResponse
.*;
import
jenkins.model.lazy.LazyBuildMixIn
;
/**
* A job is an runnable entity under the monitoring of Hudson.
...
...
@@ -570,11 +571,14 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
return
r
;
}
/**
* @see LazyBuildMixIn#createHistoryWidget
*/
protected
HistoryWidget
createHistoryWidget
()
{
return
new
HistoryWidget
<
Job
,
RunT
>(
this
,
getBuilds
(),
HISTORY_ADAPTER
);
}
p
rotected
static
final
HistoryWidget
.
Adapter
<
Run
>
HISTORY_ADAPTER
=
new
Adapter
<
Run
>()
{
p
ublic
static
final
HistoryWidget
.
Adapter
<
Run
>
HISTORY_ADAPTER
=
new
Adapter
<
Run
>()
{
public
int
compare
(
Run
record
,
String
key
)
{
try
{
int
k
=
Integer
.
parseInt
(
key
);
...
...
@@ -674,6 +678,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
/**
* @deprecated since 2008-06-15.
* This is only used to support backward compatibility with old URLs.
* @see LazyBuildMixIn#getBuild
*/
@Deprecated
public
RunT
getBuild
(
String
id
)
{
...
...
@@ -689,6 +694,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
* The build number.
* @return null if no such build exists.
* @see Run#getNumber()
* @see LazyBuildMixIn#getBuildByNumber
*/
public
RunT
getBuildByNumber
(
int
n
)
{
return
_getRuns
().
get
(
n
);
...
...
@@ -724,6 +730,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
*
* This is useful when you'd like to fetch a build but the exact build might
* be already gone (deleted, rotated, etc.)
* @see LazyBuildMixIn#getNearestBuild
*/
public
RunT
getNearestBuild
(
int
n
)
{
SortedMap
<
Integer
,
?
extends
RunT
>
m
=
_getRuns
().
headMap
(
n
-
1
);
// the map should
...
...
@@ -738,6 +745,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
*
* This is useful when you'd like to fetch a build but the exact build might
* be already gone (deleted, rotated, etc.)
* @see LazyBuildMixIn#getNearestOldBuild
*/
public
RunT
getNearestOldBuild
(
int
n
)
{
SortedMap
<
Integer
,
?
extends
RunT
>
m
=
_getRuns
().
tailMap
(
n
);
...
...
@@ -787,6 +795,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
*
* The resulting map must be treated immutable (by employing copy-on-write
* semantics.) The map is descending order, with newest builds at the top.
* @see LazyBuildMixIn#_getRuns
*/
protected
abstract
SortedMap
<
Integer
,
?
extends
RunT
>
_getRuns
();
...
...
@@ -795,11 +804,13 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
*
* The files are deleted already. So all the callee needs to do is to remove
* a reference from this {@link Job}.
* @see LazyBuildMixIn#removeRun
*/
protected
abstract
void
removeRun
(
RunT
run
);
/**
* Returns the last build.
* @see LazyBuildMixIn#getLastBuild
*/
@Exported
@QuickSilver
...
...
@@ -813,6 +824,7 @@ public abstract class Job<JobT extends Job<JobT, RunT>, RunT extends Run<JobT, R
/**
* Returns the oldest build in the record.
* @see LazyBuildMixIn#getFirstBuild
*/
@Exported
@QuickSilver
...
...
core/src/main/java/jenkins/model/lazy/LazyBuildMixIn.java
0 → 100644
浏览文件 @
c68cfc9d
/*
* The MIT License
*
* Copyright 2014 Jesse Glick.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package
jenkins.model.lazy
;
import
hudson.Extension
;
import
hudson.model.AbstractItem
;
import
hudson.model.Item
;
import
hudson.model.ItemGroup
;
import
hudson.model.Job
;
import
hudson.model.Queue.Task
;
import
hudson.model.Run
;
import
hudson.model.RunMap
;
import
hudson.model.listeners.ItemListener
;
import
hudson.widgets.BuildHistoryWidget
;
import
hudson.widgets.HistoryWidget
;
import
java.io.File
;
import
java.io.IOException
;
import
java.lang.reflect.InvocationTargetException
;
import
java.util.logging.Level
;
import
java.util.logging.Logger
;
import
javax.annotation.CheckForNull
;
import
javax.annotation.Nonnull
;
import
org.kohsuke.accmod.Restricted
;
import
org.kohsuke.accmod.restrictions.DoNotUse
;
/**
* Makes it easier to use a lazy {@link RunMap} from a {@link Job} implementation.
* Provides method implementations for some abstract {@link Job} methods,
* as well as some methods which are not abstract but which you should override.
* <p>Should be kept in a {@code transient} field in the job.
* @since TODO
*/
public
abstract
class
LazyBuildMixIn
<
P
extends
Job
<
P
,
R
>,
R
extends
Run
<
P
,
R
>>
{
private
static
final
Logger
LOGGER
=
Logger
.
getLogger
(
LazyBuildMixIn
.
class
.
getName
());
private
final
Job
<?,?>
job
;
@SuppressWarnings
(
"deprecation"
)
// [JENKINS-15156] builds accessed before onLoad or onCreatedFromScratch called
private
@Nonnull
RunMap
<
R
>
builds
=
new
RunMap
<
R
>();
// keep track of the previous time we started a build
private
long
lastBuildStartTime
;
/**
* Initializes this mixin based on a job.
* Call this from a constructor and {@link AbstractItem#onLoad} to make sure it is always initialized.
* @param job the owning job (should be of type {@code P} and assignable to {@link Task})
*/
public
LazyBuildMixIn
(
Job
<?,?>
job
)
{
this
.
job
=
job
;
}
/**
* Gets the raw model.
* Normally should not be called as such.
* Note that the initial value is replaced during {@link #onCreatedFromScratch} or {@link #onLoad}.
*/
public
final
@Nonnull
RunMap
<
R
>
getRunMap
()
{
return
builds
;
}
/**
* Same as {@link #getRunMap} but suitable for {@link Job#_getRuns}, which you <em>must override to be public</em>.
*/
public
final
RunMap
<
R
>
_getRuns
()
{
assert
builds
.
baseDirInitialized
()
:
"neither onCreatedFromScratch nor onLoad called on "
+
job
+
" yet"
;
return
builds
;
}
/**
* Something to be called from {@link AbstractItem#onCreatedFromScratch}.
*/
public
final
void
onCreatedFromScratch
()
{
builds
=
createBuildRunMap
();
}
/**
* Something to be called from {@link AbstractItem#onLoad}.
*/
@SuppressWarnings
(
"unchecked"
)
public
void
onLoad
(
ItemGroup
<?
extends
Item
>
parent
,
String
name
)
throws
IOException
{
RunMap
<
R
>
_builds
=
createBuildRunMap
();
RunMap
<
R
>
currentBuilds
=
this
.
builds
;
if
(
parent
!=
null
)
{
// are we overwriting what currently exist?
// this is primarily when Jenkins is getting reloaded
Item
current
;
try
{
current
=
parent
.
getItem
(
name
);
}
catch
(
RuntimeException
x
)
{
LOGGER
.
log
(
Level
.
WARNING
,
"failed to look up "
+
name
+
" in "
+
parent
,
x
);
current
=
null
;
}
if
(
current
!=
null
&&
current
.
getClass
()
==
job
.
getClass
())
{
try
{
currentBuilds
=
(
RunMap
<
R
>)
current
.
getClass
().
getMethod
(
"_getRuns"
).
invoke
(
current
);
}
catch
(
Exception
x
)
{
assert
false
:
"you should have made _getRuns public in "
+
job
.
getClass
();
}
}
}
if
(
currentBuilds
!=
null
)
{
// if we are reloading, keep all those that are still building intact
for
(
R
r
:
currentBuilds
.
getLoadedBuilds
().
values
())
{
if
(
r
.
isBuilding
())
{
_builds
.
put
(
r
);
}
}
}
this
.
builds
=
_builds
;
}
private
RunMap
<
R
>
createBuildRunMap
()
{
return
new
RunMap
<
R
>(
job
.
getBuildDir
(),
new
RunMap
.
Constructor
<
R
>()
{
@Override
public
R
create
(
File
dir
)
throws
IOException
{
return
loadBuild
(
dir
);
}
});
}
/**
* Type token for the build type.
* The build class must have two constructors:
* one taking the project type ({@code P});
* and one taking {@code P}, then {@link File}.
*/
protected
abstract
Class
<
R
>
getBuildClass
();
/**
* Loads an existing build record from disk.
* The default implementation just calls the ({@link Job}, {@link File}) constructor of {@link #getBuildClass}.
*/
public
R
loadBuild
(
File
dir
)
throws
IOException
{
try
{
return
getBuildClass
().
getConstructor
(
job
.
getClass
(),
File
.
class
).
newInstance
(
job
,
dir
);
}
catch
(
InstantiationException
e
)
{
throw
new
Error
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
Error
(
e
);
}
catch
(
InvocationTargetException
e
)
{
throw
handleInvocationTargetException
(
e
);
}
catch
(
NoSuchMethodException
e
)
{
throw
new
Error
(
e
);
}
}
/**
* Creates a new build of this project for immediate execution.
* Calls the ({@link Job}) constructor of {@link #getBuildClass}.
*/
@SuppressWarnings
(
"SleepWhileHoldingLock"
)
@edu
.
umd
.
cs
.
findbugs
.
annotations
.
SuppressWarnings
(
"SWL_SLEEP_WITH_LOCK_HELD"
)
public
final
synchronized
R
newBuild
()
throws
IOException
{
// make sure we don't start two builds in the same second
// so the build directories will be different too
long
timeSinceLast
=
System
.
currentTimeMillis
()
-
lastBuildStartTime
;
if
(
timeSinceLast
<
1000
)
{
try
{
Thread
.
sleep
(
1000
-
timeSinceLast
);
}
catch
(
InterruptedException
e
)
{
}
}
lastBuildStartTime
=
System
.
currentTimeMillis
();
try
{
R
lastBuild
=
getBuildClass
().
getConstructor
(
job
.
getClass
()).
newInstance
(
job
);
builds
.
put
(
lastBuild
);
return
lastBuild
;
}
catch
(
InstantiationException
e
)
{
throw
new
Error
(
e
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
Error
(
e
);
}
catch
(
InvocationTargetException
e
)
{
throw
handleInvocationTargetException
(
e
);
}
catch
(
NoSuchMethodException
e
)
{
throw
new
Error
(
e
);
}
}
private
IOException
handleInvocationTargetException
(
InvocationTargetException
e
)
{
Throwable
t
=
e
.
getTargetException
();
if
(
t
instanceof
Error
)
{
throw
(
Error
)
t
;
}
if
(
t
instanceof
RuntimeException
)
{
throw
(
RuntimeException
)
t
;
}
if
(
t
instanceof
IOException
)
{
return
(
IOException
)
t
;
}
throw
new
Error
(
t
);
}
/**
* Suitable for {@link Job#removeRun}.
*/
public
final
void
removeRun
(
R
run
)
{
if
(!
builds
.
remove
(
run
))
{
LOGGER
.
log
(
Level
.
WARNING
,
"{0} did not contain {1} to begin with"
,
new
Object
[]
{
job
,
run
});
}
}
/**
* Suitable for {@link Job#getBuild}.
*/
public
final
R
getBuild
(
String
id
)
{
return
builds
.
getById
(
id
);
}
/**
* Suitable for {@link Job#getBuildByNumber}.
*/
public
final
R
getBuildByNumber
(
int
n
)
{
return
builds
.
getByNumber
(
n
);
}
/**
* Suitable for {@link Job#getFirstBuild}.
*/
public
final
R
getFirstBuild
()
{
return
builds
.
oldestBuild
();
}
/**
* Suitable for {@link Job#getLastBuild}.
*/
public
final
@CheckForNull
R
getLastBuild
()
{
return
builds
.
newestBuild
();
}
/**
* Suitable for {@link Job#getNearestBuild}.
*/
public
final
R
getNearestBuild
(
int
n
)
{
return
builds
.
search
(
n
,
AbstractLazyLoadRunMap
.
Direction
.
ASC
);
}
/**
* Suitable for {@link Job#getNearestOldBuild}.
*/
public
final
R
getNearestOldBuild
(
int
n
)
{
return
builds
.
search
(
n
,
AbstractLazyLoadRunMap
.
Direction
.
DESC
);
}
/**
* Suitable for {@link Job#createHistoryWidget}.
*/
@SuppressWarnings
({
"unchecked"
,
"rawtypes"
})
public
final
HistoryWidget
createHistoryWidget
()
{
return
new
BuildHistoryWidget
((
Task
)
job
,
builds
,
Job
.
HISTORY_ADAPTER
);
}
@Restricted
(
DoNotUse
.
class
)
@Extension
public
static
final
class
ItemListenerImpl
extends
ItemListener
{
@Override
public
void
onLocationChanged
(
Item
item
,
String
oldFullName
,
String
newFullName
)
{
if
(
item
instanceof
Job
)
{
RunMap
<?>
builds
;
try
{
builds
=
(
RunMap
<?>)
item
.
getClass
().
getMethod
(
"_getRuns"
).
invoke
(
item
);
}
catch
(
NoSuchMethodException
x
)
{
// OK, did not override this to be public
return
;
}
catch
(
ClassCastException
x
)
{
// override it to be public but of a different type, fine
return
;
}
catch
(
Exception
x
)
{
LOGGER
.
log
(
Level
.
WARNING
,
null
,
x
);
return
;
}
builds
.
updateBaseDir
(((
Job
)
item
).
getBuildDir
());
}
}
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录