Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F98365589
HarbormasterTargetEngine.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jan 12, 12:47
Size
7 KB
Mime Type
text/x-php
Expires
Tue, Jan 14, 12:47 (2 d)
Engine
blob
Format
Raw Data
Handle
23529891
Attached To
rPH Phabricator
HarbormasterTargetEngine.php
View Options
<?php
final
class
HarbormasterTargetEngine
extends
Phobject
{
private
$viewer
;
private
$object
;
private
$autoTargetKeys
;
public
function
setViewer
(
PhabricatorUser
$viewer
)
{
$this
->
viewer
=
$viewer
;
return
$this
;
}
public
function
getViewer
()
{
return
$this
->
viewer
;
}
public
function
setObject
(
HarbormasterBuildableInterface
$object
)
{
$this
->
object
=
$object
;
return
$this
;
}
public
function
getObject
()
{
return
$this
->
object
;
}
public
function
setAutoTargetKeys
(
array
$auto_keys
)
{
$this
->
autoTargetKeys
=
$auto_keys
;
return
$this
;
}
public
function
getAutoTargetKeys
()
{
return
$this
->
autoTargetKeys
;
}
public
function
buildTargets
()
{
$object
=
$this
->
getObject
();
$viewer
=
$this
->
getViewer
();
$step_map
=
$this
->
generateBuildStepMap
(
$this
->
getAutoTargetKeys
());
$buildable
=
HarbormasterBuildable
::
createOrLoadExisting
(
$viewer
,
$object
->
getHarbormasterBuildablePHID
(),
$object
->
getHarbormasterContainerPHID
());
$target_map
=
$this
->
generateBuildTargetMap
(
$buildable
,
$step_map
);
return
$target_map
;
}
/**
* Get a map of the @{class:HarbormasterBuildStep} objects for a list of
* autotarget keys.
*
* This method creates the steps if they do not yet exist.
*
* @param list<string> Autotarget keys, like `"core.arc.lint"`.
* @return map<string, object> Map of keys to step objects.
*/
private
function
generateBuildStepMap
(
array
$autotargets
)
{
$viewer
=
$this
->
getViewer
();
$autosteps
=
$this
->
getAutosteps
(
$autotargets
);
$autosteps
=
mgroup
(
$autosteps
,
'getBuildStepAutotargetPlanKey'
);
$plans
=
id
(
new
HarbormasterBuildPlanQuery
())
->
setViewer
(
$viewer
)
->
withPlanAutoKeys
(
array_keys
(
$autosteps
))
->
needBuildSteps
(
true
)
->
execute
();
$plans
=
mpull
(
$plans
,
null
,
'getPlanAutoKey'
);
// NOTE: When creating the plan and steps, we save the autokeys as the
// names. These won't actually be shown in the UI, but make the data more
// consistent for secondary consumers like typeaheads.
$step_map
=
array
();
foreach
(
$autosteps
as
$plan_key
=>
$steps
)
{
$plan
=
idx
(
$plans
,
$plan_key
);
if
(!
$plan
)
{
$plan
=
HarbormasterBuildPlan
::
initializeNewBuildPlan
(
$viewer
)
->
setName
(
$plan_key
)
->
setPlanAutoKey
(
$plan_key
);
}
$current
=
$plan
->
getBuildSteps
();
$current
=
mpull
(
$current
,
null
,
'getStepAutoKey'
);
$new_steps
=
array
();
foreach
(
$steps
as
$step_key
=>
$step
)
{
if
(
isset
(
$current
[
$step_key
]))
{
$step_map
[
$step_key
]
=
$current
[
$step_key
];
continue
;
}
$new_step
=
HarbormasterBuildStep
::
initializeNewStep
(
$viewer
)
->
setName
(
$step_key
)
->
setClassName
(
get_class
(
$step
))
->
setStepAutoKey
(
$step_key
);
$new_steps
[
$step_key
]
=
$new_step
;
}
if
(
$new_steps
)
{
$plan
->
openTransaction
();
if
(!
$plan
->
getPHID
())
{
$plan
->
save
();
}
foreach
(
$new_steps
as
$step_key
=>
$step
)
{
$step
->
setBuildPlanPHID
(
$plan
->
getPHID
());
$step
->
save
();
$step
->
attachBuildPlan
(
$plan
);
$step_map
[
$step_key
]
=
$step
;
}
$plan
->
saveTransaction
();
}
}
return
$step_map
;
}
/**
* Get all of the @{class:HarbormasterBuildStepImplementation} objects for
* a list of autotarget keys.
*
* @param list<string> Autotarget keys, like `"core.arc.lint"`.
* @return map<string, object> Map of keys to implementations.
*/
private
function
getAutosteps
(
array
$autotargets
)
{
$all_steps
=
HarbormasterBuildStepImplementation
::
getImplementations
();
$all_steps
=
mpull
(
$all_steps
,
null
,
'getBuildStepAutotargetStepKey'
);
// Make sure all the targets really exist.
foreach
(
$autotargets
as
$autotarget
)
{
if
(
empty
(
$all_steps
[
$autotarget
]))
{
throw
new
Exception
(
pht
(
'No build step provides autotarget "%s"!'
,
$autotarget
));
}
}
return
array_select_keys
(
$all_steps
,
$autotargets
);
}
/**
* Get a list of @{class:HarbormasterBuildTarget} objects for a list of
* autotarget keys.
*
* If some targets or builds do not exist, they are created.
*
* @param HarbormasterBuildable A buildable.
* @param map<string, object> Map of keys to steps.
* @return map<string, object> Map of keys to targets.
*/
private
function
generateBuildTargetMap
(
HarbormasterBuildable
$buildable
,
array
$step_map
)
{
$viewer
=
$this
->
getViewer
();
$initiator_phid
=
null
;
if
(!
$viewer
->
isOmnipotent
())
{
$initiator_phid
=
$viewer
->
getPHID
();
}
$plan_map
=
mgroup
(
$step_map
,
'getBuildPlanPHID'
);
$builds
=
id
(
new
HarbormasterBuildQuery
())
->
setViewer
(
$viewer
)
->
withBuildablePHIDs
(
array
(
$buildable
->
getPHID
()))
->
withBuildPlanPHIDs
(
array_keys
(
$plan_map
))
->
needBuildTargets
(
true
)
->
execute
();
$autobuilds
=
array
();
foreach
(
$builds
as
$build
)
{
$plan_key
=
$build
->
getBuildPlan
()->
getPlanAutoKey
();
$autobuilds
[
$plan_key
]
=
$build
;
}
$new_builds
=
array
();
foreach
(
$plan_map
as
$plan_phid
=>
$steps
)
{
$plan
=
head
(
$steps
)->
getBuildPlan
();
$plan_key
=
$plan
->
getPlanAutoKey
();
$build
=
idx
(
$autobuilds
,
$plan_key
);
if
(
$build
)
{
// We already have a build for this set of targets, so we don't need
// to do any work. (It's possible the build is an older build that
// doesn't have all of the right targets if new autotargets were
// recently introduced, but we don't currently try to construct them.)
continue
;
}
// NOTE: Normally, `applyPlan()` does not actually generate targets.
// We need to apply the plan in-process to perform target generation.
// This is fine as long as autotargets are empty containers that don't
// do any work, which they always should be.
PhabricatorWorker
::
setRunAllTasksInProcess
(
true
);
try
{
// NOTE: We might race another process here to create the same build
// with the same `planAutoKey`. The database will prevent this and
// using autotargets only currently makes sense if you just created the
// resource and "own" it, so we don't try to handle this, but may need
// to be more careful here if use of autotargets expands.
$build
=
$buildable
->
applyPlan
(
$plan
,
array
(),
$initiator_phid
);
PhabricatorWorker
::
setRunAllTasksInProcess
(
false
);
}
catch
(
Exception
$ex
)
{
PhabricatorWorker
::
setRunAllTasksInProcess
(
false
);
throw
$ex
;
}
$new_builds
[]
=
$build
;
}
if
(
$new_builds
)
{
$all_targets
=
id
(
new
HarbormasterBuildTargetQuery
())
->
setViewer
(
$viewer
)
->
withBuildPHIDs
(
mpull
(
$new_builds
,
'getPHID'
))
->
execute
();
}
else
{
$all_targets
=
array
();
}
foreach
(
$builds
as
$build
)
{
foreach
(
$build
->
getBuildTargets
()
as
$target
)
{
$all_targets
[]
=
$target
;
}
}
$target_map
=
array
();
foreach
(
$all_targets
as
$target
)
{
$target_key
=
$target
->
getImplementation
()
->
getBuildStepAutotargetStepKey
();
if
(!
$target_key
)
{
continue
;
}
$target_map
[
$target_key
]
=
$target
;
}
$target_map
=
array_select_keys
(
$target_map
,
array_keys
(
$step_map
));
return
$target_map
;
}
}
Event Timeline
Log In to Comment