Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F98292786
DifferentialDiffExtractionEngine.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
Sat, Jan 11, 20:25
Size
8 KB
Mime Type
text/x-php
Expires
Mon, Jan 13, 20:25 (2 d)
Engine
blob
Format
Raw Data
Handle
23554283
Attached To
rPH Phabricator
DifferentialDiffExtractionEngine.php
View Options
<?php
final
class
DifferentialDiffExtractionEngine
extends
Phobject
{
private
$viewer
;
private
$authorPHID
;
public
function
setViewer
(
PhabricatorUser
$viewer
)
{
$this
->
viewer
=
$viewer
;
return
$this
;
}
public
function
getViewer
()
{
return
$this
->
viewer
;
}
public
function
setAuthorPHID
(
$author_phid
)
{
$this
->
authorPHID
=
$author_phid
;
return
$this
;
}
public
function
getAuthorPHID
()
{
return
$this
->
authorPHID
;
}
public
function
newDiffFromCommit
(
PhabricatorRepositoryCommit
$commit
)
{
$viewer
=
$this
->
getViewer
();
// If we already have an unattached diff for this commit, just reuse it.
// This stops us from repeatedly generating diffs if something goes wrong
// later in the process. See T10968 for context.
$existing_diffs
=
id
(
new
DifferentialDiffQuery
())
->
setViewer
(
$viewer
)
->
withCommitPHIDs
(
array
(
$commit
->
getPHID
()))
->
withHasRevision
(
false
)
->
needChangesets
(
true
)
->
execute
();
if
(
$existing_diffs
)
{
return
head
(
$existing_diffs
);
}
$repository
=
$commit
->
getRepository
();
$identifier
=
$commit
->
getCommitIdentifier
();
$monogram
=
$commit
->
getMonogram
();
$drequest
=
DiffusionRequest
::
newFromDictionary
(
array
(
'user'
=>
$viewer
,
'repository'
=>
$repository
,
));
$diff_info
=
DiffusionQuery
::
callConduitWithDiffusionRequest
(
$viewer
,
$drequest
,
'diffusion.rawdiffquery'
,
array
(
'commit'
=>
$identifier
,
));
$file_phid
=
$diff_info
[
'filePHID'
];
$diff_file
=
id
(
new
PhabricatorFileQuery
())
->
setViewer
(
$viewer
)
->
withPHIDs
(
array
(
$file_phid
))
->
executeOne
();
if
(!
$diff_file
)
{
throw
new
Exception
(
pht
(
'Failed to load file ("%s") returned by "%s".'
,
$file_phid
,
'diffusion.rawdiffquery'
));
}
$raw_diff
=
$diff_file
->
loadFileData
();
// TODO: Support adds, deletes and moves under SVN.
if
(
strlen
(
$raw_diff
))
{
$changes
=
id
(
new
ArcanistDiffParser
())->
parseDiff
(
$raw_diff
);
}
else
{
// This is an empty diff, maybe made with `git commit --allow-empty`.
// NOTE: These diffs have the same tree hash as their ancestors, so
// they may attach to revisions in an unexpected way. Just let this
// happen for now, although it might make sense to special case it
// eventually.
$changes
=
array
();
}
$diff
=
DifferentialDiff
::
newFromRawChanges
(
$viewer
,
$changes
)
->
setRepositoryPHID
(
$repository
->
getPHID
())
->
setCommitPHID
(
$commit
->
getPHID
())
->
setCreationMethod
(
'commit'
)
->
setSourceControlSystem
(
$repository
->
getVersionControlSystem
())
->
setLintStatus
(
DifferentialLintStatus
::
LINT_AUTO_SKIP
)
->
setUnitStatus
(
DifferentialUnitStatus
::
UNIT_AUTO_SKIP
)
->
setDateCreated
(
$commit
->
getEpoch
())
->
setDescription
(
$monogram
);
$author_phid
=
$this
->
getAuthorPHID
();
if
(
$author_phid
!==
null
)
{
$diff
->
setAuthorPHID
(
$author_phid
);
}
$parents
=
DiffusionQuery
::
callConduitWithDiffusionRequest
(
$viewer
,
$drequest
,
'diffusion.commitparentsquery'
,
array
(
'commit'
=>
$identifier
,
));
if
(
$parents
)
{
$diff
->
setSourceControlBaseRevision
(
head
(
$parents
));
}
// TODO: Attach binary files.
return
$diff
->
save
();
}
public
function
isDiffChangedBeforeCommit
(
PhabricatorRepositoryCommit
$commit
,
DifferentialDiff
$old
,
DifferentialDiff
$new
)
{
$viewer
=
$this
->
getViewer
();
$repository
=
$commit
->
getRepository
();
$identifier
=
$commit
->
getCommitIdentifier
();
$vs_changesets
=
array
();
foreach
(
$old
->
getChangesets
()
as
$changeset
)
{
$path
=
$changeset
->
getAbsoluteRepositoryPath
(
$repository
,
$old
);
$path
=
ltrim
(
$path
,
'/'
);
$vs_changesets
[
$path
]
=
$changeset
;
}
$changesets
=
array
();
foreach
(
$new
->
getChangesets
()
as
$changeset
)
{
$path
=
$changeset
->
getAbsoluteRepositoryPath
(
$repository
,
$new
);
$path
=
ltrim
(
$path
,
'/'
);
$changesets
[
$path
]
=
$changeset
;
}
if
(
array_fill_keys
(
array_keys
(
$changesets
),
true
)
!=
array_fill_keys
(
array_keys
(
$vs_changesets
),
true
))
{
return
true
;
}
$file_phids
=
array
();
foreach
(
$vs_changesets
as
$changeset
)
{
$metadata
=
$changeset
->
getMetadata
();
$file_phid
=
idx
(
$metadata
,
'new:binary-phid'
);
if
(
$file_phid
)
{
$file_phids
[
$file_phid
]
=
$file_phid
;
}
}
$files
=
array
();
if
(
$file_phids
)
{
$files
=
id
(
new
PhabricatorFileQuery
())
->
setViewer
(
PhabricatorUser
::
getOmnipotentUser
())
->
withPHIDs
(
$file_phids
)
->
execute
();
$files
=
mpull
(
$files
,
null
,
'getPHID'
);
}
foreach
(
$changesets
as
$path
=>
$changeset
)
{
$vs_changeset
=
$vs_changesets
[
$path
];
$file_phid
=
idx
(
$vs_changeset
->
getMetadata
(),
'new:binary-phid'
);
if
(
$file_phid
)
{
if
(!
isset
(
$files
[
$file_phid
]))
{
return
true
;
}
$drequest
=
DiffusionRequest
::
newFromDictionary
(
array
(
'user'
=>
$viewer
,
'repository'
=>
$repository
,
));
$response
=
DiffusionQuery
::
callConduitWithDiffusionRequest
(
$viewer
,
$drequest
,
'diffusion.filecontentquery'
,
array
(
'commit'
=>
$identifier
,
'path'
=>
$path
,
));
$new_file_phid
=
$response
[
'filePHID'
];
if
(!
$new_file_phid
)
{
return
true
;
}
$new_file
=
id
(
new
PhabricatorFileQuery
())
->
setViewer
(
$viewer
)
->
withPHIDs
(
array
(
$new_file_phid
))
->
executeOne
();
if
(!
$new_file
)
{
return
true
;
}
if
(
$files
[
$file_phid
]->
loadFileData
()
!=
$new_file
->
loadFileData
())
{
return
true
;
}
}
else
{
$context
=
implode
(
"
\n
"
,
$changeset
->
makeChangesWithContext
());
$vs_context
=
implode
(
"
\n
"
,
$vs_changeset
->
makeChangesWithContext
());
// We couldn't just compare $context and $vs_context because following
// diffs will be considered different:
//
// -(empty line)
// -echo 'test';
// (empty line)
//
// (empty line)
// -echo "test";
// -(empty line)
$hunk
=
id
(
new
DifferentialModernHunk
())->
setChanges
(
$context
);
$vs_hunk
=
id
(
new
DifferentialModernHunk
())->
setChanges
(
$vs_context
);
if
(
$hunk
->
makeOldFile
()
!=
$vs_hunk
->
makeOldFile
()
||
$hunk
->
makeNewFile
()
!=
$vs_hunk
->
makeNewFile
())
{
return
true
;
}
}
}
return
false
;
}
public
function
updateRevisionWithCommit
(
DifferentialRevision
$revision
,
PhabricatorRepositoryCommit
$commit
,
array
$more_xactions
,
PhabricatorContentSource
$content_source
)
{
$viewer
=
$this
->
getViewer
();
$result_data
=
array
();
$new_diff
=
$this
->
newDiffFromCommit
(
$commit
);
$old_diff
=
$revision
->
getActiveDiff
();
$changed_uri
=
null
;
if
(
$old_diff
)
{
$old_diff
=
id
(
new
DifferentialDiffQuery
())
->
setViewer
(
$viewer
)
->
withIDs
(
array
(
$old_diff
->
getID
()))
->
needChangesets
(
true
)
->
executeOne
();
if
(
$old_diff
)
{
$has_changed
=
$this
->
isDiffChangedBeforeCommit
(
$commit
,
$old_diff
,
$new_diff
);
if
(
$has_changed
)
{
$result_data
[
'vsDiff'
]
=
$old_diff
->
getID
();
$revision_monogram
=
$revision
->
getMonogram
();
$old_id
=
$old_diff
->
getID
();
$new_id
=
$new_diff
->
getID
();
$changed_uri
=
"/{$revision_monogram}?vs={$old_id}&id={$new_id}#toc"
;
$changed_uri
=
PhabricatorEnv
::
getProductionURI
(
$changed_uri
);
}
}
}
$xactions
=
array
();
$xactions
[]
=
id
(
new
DifferentialTransaction
())
->
setTransactionType
(
DifferentialTransaction
::
TYPE_UPDATE
)
->
setIgnoreOnNoEffect
(
true
)
->
setNewValue
(
$new_diff
->
getPHID
())
->
setMetadataValue
(
'isCommitUpdate'
,
true
);
foreach
(
$more_xactions
as
$more_xaction
)
{
$xactions
[]
=
$more_xaction
;
}
$editor
=
id
(
new
DifferentialTransactionEditor
())
->
setActor
(
$viewer
)
->
setContinueOnMissingFields
(
true
)
->
setContentSource
(
$content_source
)
->
setChangedPriorToCommitURI
(
$changed_uri
)
->
setIsCloseByCommit
(
true
);
$author_phid
=
$this
->
getAuthorPHID
();
if
(
$author_phid
!==
null
)
{
$editor
->
setActingAsPHID
(
$author_phid
);
}
try
{
$editor
->
applyTransactions
(
$revision
,
$xactions
);
}
catch
(
PhabricatorApplicationTransactionNoEffectException
$ex
)
{
// NOTE: We've marked transactions other than the CLOSE transaction
// as ignored when they don't have an effect, so this means that we
// lost a race to close the revision. That's perfectly fine, we can
// just continue normally.
}
return
$result_data
;
}
}
Event Timeline
Log In to Comment